本文章目录:
- 正则表达式的创建和使用
- 场景一:正则与数值
- 场景二:正则与颜色
- 场景三:正则与URL
正则表达式的创建和使用
一、创建正则表达式的两种方式
-
使用正则表达式字面量
const reg = /[a-z]\d+[a-z]/i
优点:简单方便;无需二次转义
缺点:子内容无法重复使用;过长的正则导致可读性变差
-
使用**
RegExp
**构造函数const alphabet = '[a-z]'; const reg = new RegExp(`${alphabet}\\d+${alphabet}`, 'i');
优点:子内容可以重复使用;可以通过控制子内容的粒度提高可读性
缺点:二次转义的问题容易导致BUG, 如:
const reg = new RegExp(`\d+`); reg.test('1'); // false reg.test('ddd'); // true
二、正则表达式的常见用法
-
RegExp.prototype.test()
判断某个字符串(若输入不是字符串,会尝试类型转换,转换失败则抛出
TypeError
)是否匹配正则表达式。若匹配,返回true,否则返回falseconst reg = /[a-z]\d+[a-z]/i; reg.test('a1a'); //true reg.test('1a1'); //false reg.test(Symbol('a1a')); // TypeError
-
RegExp.prototype.source
和RegExp.prototype.flags
分别返回当前正则表达式的模式文本字符串和当前正则表达式的修饰符的字符串(对修饰符按照字母升序排列:gimsuy)
const reg = /[a-z]\d+[a-z]/ig; reg.source; // "[a-z]\d+[a-z]" reg.flags; // "gi"
-
RegExp.prototype.exec()
和String.prototype.match()
输入:
前者要求输入字符串,遇到非字符串类型会尝试类型转换。
后者要求输入正则表达式,遇到其他类型会先尝试转换为字符串,再以字符串为
source
创建正则表达式输出:匹配成功返回匹配结果。匹配失败返回
null
const reg = /[a-z]\d+[a-z]/i; reg.exec('a1a'); // ["a1a", index: 0, input: "a1a", groups: undefined] reg.exec('1a1'); // null 'a1a'.match(reg); // ["a1a", index: 0, input: "a1a", groups: undefined] '1a1'.match(reg); // null
当正则表达式含有g修饰符时,
RegExp.prototype.exec()
每次只返回一个匹配结果,数据格式与不含g修饰符相同。而
String.prototype.match()
会返回所有匹配结果,数据格式会变为字符串数组。 -
RegExp.prototype.lastIndex
当前正则表达式最后一次匹配成功的位置(也是下一次匹配开始的位置)
const reg = /(a)/g; const str = 'a1a'; reg.lastIndex; // 0 reg.exec('a1a'); // ["a", "a", index: 0, input: "a1a", groups: undefined] reg.lastIndex; // 1 reg.exec('a1a'); // ["a", "a", index: 2, input: "a1a", groups: undefined] reg.lastIndex; // 3 reg.exec('a1a'); // null reg.lastIndex; // 0
lastIndex
不会自己重置,只有当匹配失败了只会才会重置为0。因此每次匹配之后都需要手动重置lastIndex
-
String.prototype.replace()
、String.prototype.search()
、String.prototype.split()
场景一:正则与数值
一、 一个完整的匹配数值的正则表达式
/^[+-]?(?:\d+\.?|\d*\.\d+)(?: e[+-]?\d+)?$/i
- ^:匹配字符串的开始位置
- $:匹配字符串的结束位置
- ():圆括号内为一个子表达式,当圆括号不带任何修饰符时,表示同时创建一个捕获组
- ?:匹配0或1个
- .:匹配除换行符之外的任意字符,因此匹配小数点字符时需要转义
- (?😃:创建一个非捕获组
- *****:匹配0或多个
- +:匹配1或多个
- i修饰符:忽略大小写
二、用正则处理数值
-
数值的解析
const reg = /[+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?=px|\s|$)/gi; function execNumberList(str) { reg.lastIndex = 0; //重置正则表达式的lastIndex let exec = reg.exec(str); const result = []; while (exec) { //将所有匹配所得数字加入result中 result.push(parseFloat(exec[0])); exec = reg.exec(str); } return result; } console.log(execNumberList('1.0px .2px -3px +4e1px')); // [1, 0.2, -3, 40] console.log(execNumberList('+1.0px -0.2px 3e-1px')); // [1, -0.2, 0.3] console.log(execNumberList('1px 0')); // [1, 0] console.log(execNumberList('-1e+1px')); // [-10]
- g修饰符:表示全局匹配
- (?=expression):匹配下一个表达式为expression的位置
-
数值转为货币
const reg = /(\d)(?=(\d{3})+(,|$))/g; function formatCurrency(str) { return str.replace(reg, '$1,'); } console.log(formatCurrency('1')); // 1 console.log(formatCurrency('123')); // 123 console.log(formatCurrency('12345678')); // 12,345,678
- {n}:表示重复n次
- {n,m}:重复n到m次
- {n,}:重复至少n次
- $n:用于
replace
的字符串中,表示第n个捕获组。n可以为从1到9
场景二:正则与颜色
一、颜色的表示方式
- 16进制表示法,如 #fff、#abceee、#15573
- rgb/rgba表示法,如 rgb(r, g, b)、rgb(r%, g%, b%)
- 其他
二、使用正则处理颜色
16进制颜色优化
const hex = '[0-9a-z]';
const hexReg = new RegExp(`^#(?<r>${hex})\\k<r>(?<g>${hex})\\k<g>(?<b>${hex})\\k<b>(?<a>${hex}?)\\k<a>$`, 'i');
function shortenColor(str) {
return str.replace(hexReg, '#$<r>$<g>$<b>$<a>');
}
console.log(shortenColor('#336600')); // '#360'
console.log(shortenColor('#19b955')); // '#19b955'
console.log(shortenColor('#33660000')); // '#3600'
场景三:正则与URL
一、用正则解析URL
const protocol = '(?<protocol>https?:)';
const host = '(?<host>(?<hostname>[^/#?:]+)(?::(?<port>\\d+))?)';
const path = '(?<pathname>(?:\\/[^/#?]+)*\\/?)';
const search = '(?<search>(?:\\?[^#]*)?)';
const hash = '(?<hash>(?:#.*)?)';
const reg = new RegExp(`^${protocol}\/\/${host}${path}${search}${hash}$`);
function execURL(url) {
const result = reg.exec(url);
if (result) {
result.groups.port = result.groups.port || '';
return result.groups;
}
return {
protocol: '', host: '', hostname: '', port: '',
pathname: '', search: '', hash: '',
};
}
console.log(execURL('https://www.360.cn'));
console.log(execURL('http://localhost:8080/?#'));
console.log(execURL('https://image.so.com/view?q=360&src=srp#id=9e17bd&sn=0'));
console.log(execURL('this is not a url'));
二、用正则解析hash和search
function execUrlParams(str) {
str = str.replace(/^[#?&]/, '');
const result = {};
if (!str) {
return result;
}
const reg = /(?:^|&)([^&=]*)=?([^&]*?)(?=&|$)/y;
let exec = reg.exec(str);
while (exec) {
result[exec[1]] = exec[2];
exec = reg.exec(str);
}
return result;
}
console.log(execUrlParams('#')); // { }
console.log(execUrlParams('##')); // { '#': '' }
console.log(execUrlParams('?q=360&src=srp')); // { q: '360', src: 'srp' }
console.log(execUrlParams('test=a=b=c&&==&a=')); // { test: 'a=b=c', '': '=', a: '' }
Node.js基础入门
什么是Node.js
Node.js® is a JavaScript runtime built on Chrome’s V8 JavaScript engine.
与JavaScript的区别
- 基于异步I/O相关接口
- 基于 node_modules 和 require 的模块依赖
- 提供 C++ addon API 与系统交互
Node.js基础
模块
- 内置模块:编译进Node中,比如
http
、fs
、net
、process
、path
- 文件模块:原生模块之外的模块,和文件(夹)一一对应。
一个使用内置模块的例子:
const fs = require('fs');
fs.readFile('a.txt', (err, buffer) => {
console.log(buffer);
});
//或者
const { readFile } = require('fs');
readFile('a.txt', (err,buffer) => {
console.log(buffer);
});
一个使用文件模块的例子:
//app.js
var circle = require('./circle.js');
console.log('半径为4的圆面积是:' + circle.area(4));
//circle.js
const pi = Math.PI;
exports.area = function(r) {
return pi * r * r;
};
exports.circumference = function(r) {
return 2 * pi * r;
};
加载模块的方法:
//绝对路文件
require('/foo/bar/a.js');
//相对路径文件
require('./a.js');
//无后缀文件
require('./a');
//外部模块
require('pkg-name');
Node.js Web开发
-
API开发 使用
RESTful API
RESTful API
接口规范- 每个API都对应一种资源或者资源集合
- 使用
HTTP Method
来表示对资源的动作 - 使用
HTTP Status Code
来表示资源操作结果