正则学习
Regular 正则
什么是正则
正则是一个规则,用来处理字符串的规则
正则匹配
编写一个规则,验证某个字符串是否符合这个规则,正则匹配使用的是 test 方法
正则捕获
编写一个规则,在一个字符串中吧符合规则的内容捕获取到,正则捕获使用的方法: 正则的 exec 方法、字符串的 split 方法、字符串的 split 、replace 、match 等方法都支持正则
正则的简单语法
let reg = /^$/; // 两个斜杆中间包含一些内容就是正则,两个斜杆之间包含的全部内容就是元字符
正则的元字符和修饰符
任何一个正则都是由元字符和修饰符组成
修饰符(img)
- g (gloal)
全局匹配
- i (ignoreCase)
忽略大小写匹配
- m (multiline)
多行匹配
元字符
量词元字符
- + 让前面的元字符出现
一到多次
- ? 让前面的元字符出现
一次
- * 让前面的元字符出现
零到一次
- { n } 让前面的元字符出现
n次
- { n, } 让前面的元字符出现
n到多次
- { n, m } 让前面的元字符出现
n到m次
- + 让前面的元字符出现
特殊意义的元字符
- \ 转义字符, 把一个有意义的字符转换为普通字符, 或者将一个普通字符转换为特殊字符
- . 除了
\n
以外的任意字符 - \d 匹配一个
0-9
之间的数字 - \D 匹配任意一个
非 0-9
之间的数字 - \w 匹配一个
0-9或者字母或者_
之间的字符 - \s 匹配一个任意
空白
字符 - \b 匹配一个
边界
符 - x | y 匹配
x 或者 y
中的一个 - [ a-z ] 匹配
a-z
中的任意一个 - [ ^ a-z ] 匹配任意一个
非 a-z
的字符 - [xyz] 匹配
xyz
中的一个字符 - [^xyz] 匹配 任意一个
非xyz
中的字符 - () 正则的小分组,匹配 一个小分组
- ^ 以某
一个元字符开始
- $ 以某
一个元字符结束
- ?: 只匹配不捕获
- ?= 正向预查
- ?! 反向预查
除了以上的特殊元字符和量词元字符,其余的都叫普通元字符: 代表本身意义的元字符 (abc...)
- g (gloal)
元字符代码详解
\d
let reg = /\d+/; let str = 'demo200demo'; reg.test(str); // true
let reg = /^\d+/;
let str = 'demo202';
reg.test(str); // falselet reg = /^\d+$/;
let str = '123dempo13w2';
reg.test(str); // falselet reg = /^2.3$/;
reg.test('2.3'); // true// 将其转换为普通字符
let reg = /^\d$/;
reg.test('d'); // false
reg.test('\d'); // false
reg.test('\d'); // truelet reg = /^\\d$/; // \ \d
reg.test("\0"); // true
x|y
let reg = /^18|19$/; reg.test("1819"); // true reg.test('181'); // true
() 的作用
- 可以改变一个默认的优先级
- 分组引用
\1 或者 \2 出现的和第n个分组一模一样的内容
let reg = /^([a-z])([a-z])\2([a-z])$/; reg.test('food'); // good weel book foot week eggs let numberReg = /^-?(\d|([1-9]\d+))(\.\d+)?$/;
- 分组捕获
[]
- 中括号出现的元字符,一般都代表本身的含义
let reg = /^[.?+]+$/; // .?+ 代表本身
- 案例 :定义一个描述样式类名的规则
let reg = /^\w[\w-]*$/;
- 案例: 判断用户输入的年龄只能在18-69之间
let reg = /^((18|19)|([2-5]\d)|(6[0-5]))$/;
- 案例: 身份证
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})(?:\d{2})(\d)(?:\d|X)$/; let str = '445224199811124058'; reg.exec(str);
验证中文汉字的正则
let reg = /^[\u4E00-\u9FA5]$/
正则捕获详解
把当前字符串中符合正则的字符捕获到
RegExp.prototype
exec
实现正则的捕获方法let reg = /\d+/; let str = 'korea123'; reg.exec(str); /* 当正则匹配的时候: 1. 先去验证当前的字符串是否和正则匹配,如果不匹配放回的结果是null 2. 如果匹配,从字符串最左边开始,向右查找到匹配的内容,并且把匹配的内容返回 exec捕获到结果的格式: 获取的结果是一个数组 数组中的第一项是当前本次大正则在字符串中匹配到的结果 执行一次exec只能把符合正则条件中的一项捕获到 */
正则捕获存在懒惰性
执行一次exec捕获到第一个符合规则的内容,再次执行exec,返回的结果依然是第一次捕获到的结果。
解决正则捕获的懒惰性
在正则的末尾加修饰符 g (全局匹配)
正则捕获存在懒惰性原因
- 正则本身有一个属性: lastIndex (下一次正则在字符串中匹配查找的开始索引)
- 默认值为0, 从第一个字符查找匹配的内容
- 默认不管制定多少遍exec方法,正则的lastIndex都不会变
- 手动修改lastIndex进行修改时,不会起到任何作用
加修饰符 g解决懒惰性原因
加了修饰符 g 之后。每一次执行完 exec,浏览器默认会把lastIndex的值进行修改,下一次从上一次结束的位置进行查找,所以可以获取到后面匹配的内容
exec局限性
- 执行一次exec只能捕获到一个正则匹配的结果(即使加了修饰符),如果需要都捕获到,需要执行n次才能捕获到;
- 封装execAll方法,执行一次该方法,可以把当前正则匹配到的全部内容都捕获到
RegExp.prototype.execAll = function execAll() { let str = arguments[0] || '', result = [], ary = this.exec(str); if(!this.global) { return this.exec(str); } while (ary) { result.push(ary[0]); ary = this.exec(str); } return result; }
let reg = /\d+/;
let str = 'korea2019demo2020';
console.log(reg.execAll(str));
使用字符串方法 match 实现捕获
- 代码实现
let reg = /\d+/g; let str = 'demo210korea220';
console.log(str.match(reg));
使用match进行捕获
- 如果正则加了修饰符 g,执行一次会把所有正则匹配的内容捕获到
- 如果没有,执行一次match只能捕获把第一次匹配的容捕获到
局限性
在加了修饰符的情况下,执行match方法只能把大正则匹配的内容捕获到。对于小分组的容方法会给其自忽略
使用 test 实现正则捕获
- 不管是正则的匹配还是正则的捕获,在处理的时候原理是没有区别的:
从字符串的第一个字符向后查找,找到符合正则规则的字符,如果可以找到,说明正则和字符串匹配,(test检测返回true exec捕获返回的内容,如果找到末尾没有匹配的,说明正则和字符串不匹配(test检测返回false, exec 捕获返回null)
- 如果正则设置了修饰符g,不管你使用test还是exec中的任何方法,都会修改lastIndex的值,下一次查找是基于上一次匹配结果的末尾进行查找
- 不管是正则的匹配还是正则的捕获,在处理的时候原理是没有区别的:
split
- 在使用split进行字符串拆分的时候,如果正则中包含小分组,会把小分组的内容都捕获到,放在最后的数组中
案例:
let str = 'name=korea&age=20&id=20170303118'; let result = str.split(/(?:&|=)/); // 匹配不捕获 console.log(result);
replace
- 字符串中原有字符的替换
- 在不使用正则的情况下,执行一次只能替换一个原有的字符
replace原理
当replace方法执行,第一项传递一个正则
正则不加 g: 把当前第一个和正则匹配的结果捕获到,替换成新的字符
正则加 g: 把当前字符串的所有和正则匹配的容都替换
当replace执行第二个参数传递的是一个函数时
- 首先用正则到字符串中进行匹配,匹配到一个符合规则的,就把传递的函数执行一次,不仅智执行这个函数,而且还把正则本次捕获到结果 当做实参传递给
边界符
let str = 'my name is lu-korea'; str = str.replace(/-/g, '_'); str = str.replace(/\b(\w)(\w*)\b/g, (...args) => { return args[1].toUpperCase() + args[2]; }); str = str.replace(/_/g, "-"); console.log(str);
formatTime
1. 方法一 let date = '2019-11-15 2:03:17'; let reg = /^(\d{4})-(\d{1,2})-(\d{1,2})\s+(\d{1,2}):(\d{1,2}):(\d{1,2})$/g; date = date.replace(reg, (...args) => { return `${args[1]}年${args[2]}月${args[3]}日 ${args[4]}时${args[5]}分${args[6]}秒`; });
date = date.replace(reg, '$1年$2月$3日 $4时$5分$6秒')
console.log(date);
2. 方法二
String.prototype.formatDate = function formatDate () {
let array = this.match(/\d+/g),
template = arguments[0] || '{0}年{1}月{2}日 {3}时{4}分{5}秒';
template = template.replace(/{(\d+)}/g, (...args) => {
let value = array[args[1]] || '0';
value.length < 2 ? value = '0' + value : null;
return value;
});
return template;
}let str = new Date().toLocaleString();
str = str.formatDate();console.log(str);
去除收尾空格
let tirmStr = (str) => { return str.replace(/^\s+|\s+$/g, ''); }
console.log(tirmStr(' demo demo '));
解析URL参数
let parseURL = (url) => { let obj = {}; url.replace(/([^&?=#]+)=([^&?=#]+)/g, (...args) => { obj[args[1]] = args[2]; }); url.replace(/#([^&?=]+)/g, (...args) => { obj['hash'] = args[1]; }); return obj; }
console.log(parseURL('http://www.baidu/com?name=korea&age=20#student'));
所有支持正则的方法都可以实现正则的捕获(一般都是字符串的方法)