前言
本篇多以网上资料参考及个人理解为主,希望能帮助到大家,当然在不足的地方请多多包含。
一、介绍
正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。
二、特点
- 灵活性、逻辑性和功能性非常强;
- 可以迅速地用极简单的方式达到字符串的复杂控制。
三、元字符与修饰符
1、元字符
\ ^ $ . * + ? \d \D \w \W \s \S {n} {n,} {n, m} 等
2、修饰符
字符 | 描述 |
---|---|
i | 不区分大小写 |
g | 全局匹配 |
四、优先级
运算符 | 描述 |
---|---|
\ | 转义符 |
(), (?:), (?=), [] | 圆括号和方括号 |
*, +, ?, {n}, {n,}, {n,m} | 限定符 |
^, $, \任何元字符、任何字符 | 定位点和序列(即:位置和顺序) |
| | 替换,"或"操作,字符具有高于替换运算符的优先级,使得"m|food"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。 |
五、实例方式
1、/pattern/ (比较常用)
/he/.test('hello') // true
2、new RegExp (可传变量)
var char = 'e';
new RegExp('h'+char).test('hello'); // true
六、常用匹配方法
1、test() 方法用于检测一个字符串是否匹配某个模式。返回true/false
/he/.test('hello') // true
2、match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。返回匹配结果数组或null
a、无匹配结果
var str = 'hello world ~';
var result = str.match(/z/); // null
b、无g修饰符(只输出第一个匹配结果)
var str = 'aaa_aa_a';
var pattern = /a+/;
console.log(str.match(pattern)); // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
console.log(str.match(pattern)); // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
c、有g修饰符(输出所有匹配结果)
var str = 'hello world ~';
var result = str.match(/o/g); // ["o", "o"]
3、exec() 方法用于检索字符串中的正则表达式的匹配。返回匹配结果数组或null
a、无匹配结果
var str = 'hello world ~';
var result = /z/.exec(str); // null
b、无g修饰符(只输出第一个匹配结果,这点同match一样)
var str = 'aaa_aa_a';
var pattern = /a+/;
console.log(pattern.exec(str)); // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
console.log(pattern.exec(str)); // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
c、有g修饰符(会记住上一次匹配结果的位置,查找下一个匹配,可以反复调用,直接到没匹配结果)
var str = 'aaa_aa_a';
var pattern = /a+/g;
console.log(pattern.exec(str)) // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
console.log(pattern.exec(str)) // ["aa", index: 4, input: "aaa_aa_a", groups: undefined]
console.log(pattern.exec(str)) // ["a", index: 7, input: "aaa_aa_a", groups: undefined]
console.log(pattern.exec(str)) // null
4、search() 方法用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。返回匹配子字符串的第一个索引位置或-1,这点同indexOf方式类似
a、有匹配结果
var str = 'hello world ~';
var result = str.search(/o/g); // 4
b、无匹配结果
var str = 'hello world ~';
var result = str.search(/z/); // -1
5、replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。返回一个替换过的新字符串
var str = 'hello world ~';
str = str.replace(/hello/, 'hi');
console.log(str); // hi world ~
6、split() 方法用于把一个字符串分割成字符串数组。返回一个字符串数组
var str = 'hello world ~';
var arr = str.split(/o/);
console.log(arr); // ["hell", " w", "rld ~"]
7、compile() 方法也可用于改变和重新编译正则表达式。
var str = 'hello World.';
var pattern = /wo/;
console.log(new RegExp(pattern).test(str)); // 结果:false
var pattern2 = pattern.compile(/wo/i);
console.log(new RegExp(pattern).test(str)); // 结果:true
七、获取匹配结果
将( 和 ) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。
1、RegExp.$1 ($2,$3...)
var str = 'hello world ~';
var result = /(he)(l)/.test(str);
console.log(RegExp.$1, RegExp.$2); // he l
2、groups分组起名(ES6)
var pattern = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;
var result = pattern.exec('2017-01-25');
![](https://img.haomeiwen.com/i2114039/ef0f1bd894bf469d.jpg)
也可以解析赋值
var {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
console.log(one, two); // foo bar
八、贪婪模式与惰性模式
1、贪婪模式(默认)
限定符:+, ?, *, {n}, {n,}, {n,m}
var pattern = /8[a-zA-Z0-9]*7/g;
var string = "abc8defghij7klngon8qrstwxy7";
console.log(string.match(pattern)) // ["8defghij7klngon8qrstwxy7"]
2、惰性模式
标识符:+?, ??, *?, {n}?, {n,}?, {n,m}? (在限定符后加?)
var pattern = /8[a-zA-Z0-9]*?7/;
var string = "abc8defghij7klngon8qrstwxy7";
console.log(string.match(pattern)) // ["8defghij7"]
九、获取匹配与非获取匹配
1、获取
规则 | 描述 | 示例 |
---|---|---|
(pattern) | 匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在JScript中则使用 |
RegExp.$1 |
var result = /(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)/.test('abcdefghijklmn');
console.log(RegExp.$0); // undefined
console.log(RegExp.$1); // a
console.log(RegExp.$9); // i
console.log(RegExp.$10); // undefined
2、非获取
规则 | 描述 |
---|---|
(?:pattern) | 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。 |
/industr(?:y|ies)/.test('industried') // false
/industr(?:y|ies)/.test('industry') // true
console.log(RegExp.$1); // 没有任何内容
上面匹配相当于这样,只不过是把公共部分拿出来了而已
/industry|industries/.test('industried') // false
规则 | 描述 |
---|---|
(?=pattern) | 非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。 |
/Windows(?=95|98|NT|2000)/.test('acbWindowsXPfff') // false
/Windows(?=95|98|NT|2000)/.test('acbWindowsNTfff') // true
规则 | 描述 |
---|---|
(?!pattern) | 非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。 |
/Windows(?!95|98|NT|2000)/.test('abcWindows98') // false
/Windows(?!95|98|NT|2000)/.test('abcWindowsXP') // true
规则 | 描述 |
---|---|
(?<=pattern) | 非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。 |
/(?<=95|98|NT|2000)Windows/.test('abcXPWindows') // false
/(?<=95|98|NT|2000)Windows/.test('abc98Windows') // true
规则 | 描述 |
---|---|
(?<!patte_n) | 非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。 |
/(?<!95|98|NT|2000)Windows/.test('abc2000Windows') // false
/(?<!95|98|NT|2000)Windows/.test('abcXPWindows') // true
3、结合贪婪示例
var b = "abeeee:eeeee:eeeeeab";
console.log(b.match(/e+\:e+/g)); // ["eeee:eeeee"]
console.log(b.match(/e+\:e+?/g)); // ["eeee:e", "eeee:e"]
console.log(b.match(/e+\:(?=e+)/g)); // ["eeee:", "eeeee:"]
console.log(b.match(/e+?\:(?=e+)/g)); // ["eeee:", "eeeee:"]
console.log(b.match(/e+?\:(?!e+)/g)); // null
console.log(b.match(/(?:e+)?\:(?:e+?)/g)); // ["eeee:e", "eeee:e"]
十、开发常用
1、匹配1-5个中文
/^[\u4E00-\u9FA5]{1,5}$/.test('张三'); // true
2、匹配邮箱
/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test('abc@123.com'); // true
3、sublime编辑器中字符串替换
把import引入方式替换成require引入方式
let Home = ()=>import('@/pages/home')
let About = ()=>import('@/pages/about')
let List = ()=>import('@/pages/List')
规则
\(\)=>import\('(.*)'\)
require "$1";
![](https://img.haomeiwen.com/i2114039/dceedd5a91922aa1.jpg)
4、匹配数字
var price = 120.36;
console.log(/^\d+\.?\d+$/.test(price)); // true
5、匹配手机号
/^1[3|4|5|7|8][0-9]{9}$/.test(18235661888); // true
6、匹配所有空白行
规则
^\s*\n
![](https://img.haomeiwen.com/i2114039/32e9c74d2d661d95.jpg)
7、获取url参数值
假定url为:file:///E:/xampp/htdocs/test/test.html?name=tom&age=24 获取name值
/(?<=name=)\w+/.exec(location.href) // ["tom",...]
8、tab转空格
\t
十一、不常用匹配
1、\cx元字符
匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。
console.log(/\cM/.test("回车符\r")); // true
2、\num
匹配num,其中num是一个正整数。对所获取的匹配的引用。例如,“(.)\1”匹配两个连续的相同字符。
a、示例:字符串去重
var str = 'a,a,b,b,b,cc';
console.log(str.replace(/(\w,).*\1/g, '$1')); // a,b,cc
上面代码需要连续重复才行,是有条件约束的,不然像下面的代码就不是自己想要的了。
var str = 'a,a,b,b,d,b,cc';
console.log(str.replace(/(\w,).*\1/g, '$1')); // a,b,cc
\1表示重复正则第一个圆括号内匹配到的内容
\2表示重复正则第二个圆括号内匹配到的内容
以此类推
/(h)(e)\1\2/g.test('hehello') // true
/(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\10/g.test('abcdefghijjklmn') // true
3、\xn匹配16进制字符
匹配n,其中n为十六进制转义值
/\x41/.exec('A') // ["A", index: 0, input: "A", groups: undefined]
'A'.charCodeAt() // 十进制65
'A'.charCodeAt().toString(16) // 十进制65 转十六进制为41
parseInt(41, 16) // 16进制的41 转十进制为65
String.fromCharCode(65) // A
![](https://img.haomeiwen.com/i2114039/58ad29da8493358d.jpg)
十二、正则模拟js方法
1、indexOf()查找子符开始位置索引
使用search实现
'hello'.indexOf('e'); // 1
'hello'.search(/e/); // 1
2、trim()去除前后空格
使用replace实现
' hello '.trim(); // hello
' hello '.replace(/^\s+|\s+$/g, ''); // hello
3、isNaN判断是否是一个数字
console.log(isNaN(123)); // false
console.log(isNaN(-1.23)); // false
console.log(isNaN(5-2)); // false
console.log(isNaN(0)); // false
console.log(isNaN("Hello")); // true
console.log(isNaN("2005/12/12")); // true
var pattern = /^\-?\d+[.-]?(\d+)?$/;
console.log(!pattern.test(123)); // false
console.log(!pattern.test(-1.23)); // false
console.log(!pattern.test(5-1.2)); // false
console.log(!pattern.test(0)); // false
console.log(!pattern.test('Hello')); // true
console.log(!pattern.test('2005/12/12')); // true
十三、jQuery正则剖析
1、trim去除字符前后空格
var trim = function(string) {
return (string || '').replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
\s:空格
\uFEFF:字节次序标记字符(Byte Order Mark),也就是BOM,它是es5新增的空白符
\xA0:禁止自动换行空白符,相当于html中的
2、匹配parents/prevUntil/prevAll
var pattern = /^(?:parents|prev(?:Until|All))/;
console.log(pattern.exec('parent')); // null
console.log(pattern.exec('parents')); // ["parents", index: 0, input: "parents", groups: undefined]
console.log(pattern.exec('parentsUntil')); // ["parents", index: 0, input: "parentsUntil", groups: undefined]
console.log(pattern.exec('prev')); // null
console.log(pattern.exec('prevUntil')); // ["prevUntil", index: 0, input: "prevUntil", groups: undefined]
console.log(pattern.exec('prevAll')); // ["prevAll", index: 0, input: "prevAll", groups: undefined]
![](https://img.haomeiwen.com/i2114039/a788f2ab521c2021.jpg)
3、匹配标签
var pattern = /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>)$/i;
// ^< 以<开头
// ([a-z][^\/\0>:\x20\t\r\n\f]*) 第一组 两个集合[a-z]、[^\/\0>:\x20\t\r\n\f]及*匹配前面的子表达式任意次 \x20空格
// [\x20\t\r\n\f]*
// \/?> 有没有/都可以,如<b>或<b/>
// (?:<\/\1>|)$ ?:非获取匹配 \1表示前面的组,也就是重复前端的规则,>结尾
console.log(pattern.exec('<b>')); // ["<b>", "b", index: 0, input: "<b>", groups: undefined]
console.log(pattern.exec('<div/>')); // ["<div/>", "div", index: 0, input: "<div/>", groups: undefined]
console.log(pattern.exec('<div\0>')); // null
console.log(pattern.exec('<div>>')); // null
console.log(pattern.exec('<div:>')); // null
console.log(pattern.exec('<div\n>')); // null
console.log(pattern.exec('<div></div>')); // ["<div></div>", "div", index: 0, input: "<div></div>", groups: undefined]
console.log(pattern.exec('<div>hello</div>')); // null
转义字符 | 意义 | ASCII码值(十进制) |
---|---|---|
\a | 响铃(BEL) | 007 |
\b | 退格(BS) ,将当前位置移到前一列 | 008 |
\f | 换页(FF),将当前位置移到下页开头 | 012 |
\n | 换行(LF) ,将当前位置移到下一行开头 | 010 |
\r | 回车(CR) ,将当前位置移到本行开头 | 013 |
\t | 水平制表(HT) (跳到下一个TAB位置) | 009 |
\v | 垂直制表(VT) | 011 |
\\ | 代表一个反斜线字符''' | 092 |
\' | 代表一个单引号(撇号)字符 | 039 |
\" | 代表一个双引号字符 | 034 |
\? | 代表一个问号 | 063 |
\0 | 空字符(NUL) | 000 |
\ddd | 1到3位八进制数所代表的任意字符 | 三位八进制 |
\xhh | 1到2位十六进制所代表的任意字符 | 二位十六进制 |
十四、ES6扩展
1、RegExp参数扩展
new RegExp('he', 'i').test('HEllo') // true
new RegExp(/he/i).test('HEllo') // true
new RegExp(/he/i, 'g').test('HEllo') // false 因为前面的修饰符i会被后面的g代替,所以返回false
2、\u修饰符
含义为“Unicode 模式”,用来正确处理大于\uFFFF的 Unicode 字符。也就是说,会正确处理四个字节的 UTF-16 编码。
/^\uD83D/u.test('\uD83D\uDC2A') // false \uD83D\uDC2A是一个四个字节的 UTF-16 编码,代表一个字符
/^\uD83D/.test('\uD83D\uDC2A') // true ES5 不支持四个字节的 UTF-16 编码,会将其识别为两个字符,所以返回true
a、点字符
对于码点大于0xFFFF的 Unicode 字符,点字符不能识别,必须加上u修饰符。
var str = '𠮷';
/^.$/.test(str) // false
/^.$/u.test(str) // true
b、Unicode 字符表示法
这种表示法在正则表达式中必须加上u修饰符,才能识别当中的大括号,否则会被解读为量词。
/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true
c、i修饰符
有些 Unicode 字符的编码不同,但是字型很相近,比如,\u004B与\u212A都是大写的K。
/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true
d、RegExp.prototype.unicode属性
判断是否设置了u修饰符
var pattern = /hello/u;
console.log(pattern.unicode); // true
3、y修饰符
y修饰符,叫做“粘连”(sticky)修饰符。
y修饰符的作用与g修饰符类似,也是全局匹配,后一次匹配都从上一次匹配成功的下一个位置开始。不同之处在于,g修饰符只要剩余位置中存在匹配就可,而y修饰符确保匹配必须从剩余的第一个位置开始,这也就是“粘连”的涵义。
var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;
console.log(r1.exec(s)); // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
console.log(r1.exec(s)); // ["aa", index: 4, input: "aaa_aa_a", groups: undefined]
console.log(r1.exec(s)); // ["a", index: 7, input: "aaa_aa_a", groups: undefined]
console.log(r2.exec(s)); // ["aaa", index: 0, input: "aaa_aa_a", groups: undefined]
console.log(r2.exec(s)); // null
这样改变一个规则,y修饰符就会返回结果了
var s = 'aaa_aa_a';
var r = /a+_/y;
console.log(r.exec(s)); // ["aaa_", index: 0, input: "aaa_aa_a", groups: undefined]
console.log(r.exec(s)); // ["aa_", index: 4, input: "aaa_aa_a", groups: undefined]
console.log(r.exec(s)); // null
实例:替换规定条件文本
console.log('aaxa'.replace(/a/gy, '-')); // '--xa'
上面代码中,最后一个a因为不是出现在下一次匹配的头部,所以不会被替换。
a、RegExp.prototype.sticky属性
判断是否设置了y修饰符
var r = /hello\d/y;
console.log(r.sticky); // true
4、RegExp.prototype.flags属性
a、ES5 的 source 属性,返回正则表达式的正文
console.log(/abc/ig.source); // abc
b、flags 属性,返回正则表达式的修饰符
console.log(/abc/ig.flags); // ig
5、断言
a、先行断言(ES5)
”先行断言“指的是,x只有在y前面才匹配,必须写成/x(?=y)/。
console.log(/\d+(?=%)/.exec('abc 100% efg')); // ["100", index: 4, input: "abc 100% efg", groups: undefined]
console.log(/\d+(?!%)/.exec('abc 44 efg')); // ["44", index: 4, input: "abc 44 efg", groups: undefined]
b、后行断言(ES6)
“后行断言”正好与“先行断言”相反,x只有在y后面才匹配,必须写成/(?<=y)x/。
console.log(/(?<=%)\d+/.exec('abc %100 efg')); // ["100", index: 5, input: "abc %100 efg", groups: undefined]
6、Unicode属性类
允许正则表达式匹配符合 Unicode 某种属性的所有字符。
var pattern = /\p{Script=Greek}/u;
console.log(pattern.test('π')); // true
上面代码中,\p{Script=Greek}指定匹配一个希腊文字母,所以匹配π成功。
对于某些属性,可以只写属性名,或者只写属性值。
\p{UnicodePropertyName}
\p{UnicodePropertyValue}
\P{…}是\p{…}的反向匹配,即匹配不满足条件的字符。
7、引用
var pattern = /^(?<word>[a-z]+)!\k<word>$/;
console.log(pattern.test('abc!abc')); // true
或者\1依然有效
var pattern = /^(?<word>[a-z]+)!\1$/;
console.log(pattern.exec('abc!abc'));
![](https://img.haomeiwen.com/i2114039/329918914acc89a3.jpg)
8、String.prototype.matchAll
可以一次性取出所有匹配。不过,它返回的是一个遍历器(Iterator),而不是数组。
const string = 'test1test2test3';
// g 修饰符加不加都可以
const regex = /t(e)(st(\d?))/g;
for (const match of string.matchAll(regex)) {
console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
参考连接:
ES6正则扩展:http://es6.ruanyifeng.com/#docs/regex
ASCII码对照表:http://ascii.911cha.com/
Unicode码对照表:https://www.cnblogs.com/chris-oil/p/8677309.html
网友评论