正则表达式
正则表达式(Regular Expression,在代码中常简写为 regex、regexp 或 RE)应用单个字符串来形容、匹配一系列合乎某个句法规定的字符串搜寻模式。
1. 什么是正则表达式?
正则表达式是由一个字符序列造成的搜寻模式。
你在文本中搜寻数据时,你能够用搜寻模式来形容你要查问的内容。
正则表达式能够是一个简略的字符,或一个更简单的模式。
正则表达式可用于所有文本搜寻和文本替换的操作。
2. 正则表达式的创立
-
字面量(间接量)
// 在一对反斜线中写正则表达式内容,如 /abc/
// 正则表达式外面不须要加引号 不论是数字型还是字符串型
var reg = / 正则表达式 / 修饰符;
var reg = /hello/g;
-
构造函数
// 结构正则表达式的实例,如 new RexExp('abc')
// 外部传入的参数为字符串 / 字符串的变量
var reg =new RegExp("正则表达式","修饰符")
var reg =new RegExp("hello","g");
3. 字符分类
一般字符
字母、数字、下划线、汉字、没有非凡含意的符号(, ; ! @等)
实际上不是特殊字符的字符都是一般字符
特殊字符
\:将特殊字符本义成一般字符
模式修饰符
i:ignoreCase,匹配时漠视大小写
m:multiline,多行匹配
g:global,全局匹配
字面量创立正则时,模式修饰符写在 一对反斜线后
4. 正则表达式实例办法
-
exec
可用来匹配字符串中合乎正则表达式的字符串
如果匹配到,返回值是一个 result 数组:
[匹配的内容,index: 在 str 中匹配的起始地位,input: 参数字符串,groups: undefined]
否则返回 null
var str = 'hello world hello';
var reg1 = /hello/;
var reg2 = /hello/g;
var reg3 = /exe/g;
console.log(reg1.exec(str)); //['hello', index: 0, input: 'hello world hello', groups: undefined]
console.log(reg2.exec(str)); //['hello', index: 0, input: 'hello world hello', groups: undefined]
console.log(reg3.exec(str)); // null
// 如果是全局模式的正则验证 还能够应用循环进行输入
while(true)
var result = reg.exec(str);
if(!result){break;}
console.log(result[0],result["index"],reg.lastIndex);
}
留神点:
1)如果正则表达式中有修饰符 ”g”, 这时,在正则表达式的实例 reg 中会保护 lastIndex 属性,记录下一次开始的地位,当第二次执行 exec 的时候,从 lastIndex 开始检索。
2)如果正则表达式中没有修饰符 ”g”, 不会保护 lastIndex 属性,每次执行从开始地位检索
-
test
用来测试待检测的字符串中是否有能够匹配到正则表达式的字符串,如果有返回 true,否则返回 false
var str = 'hello world';
var reg1 = /world/;
var reg2 = /Regex/;
console.log(reg1.test(str)); // 返回 true
console.log(reg2.test(str)); // 返回 false
留神点:
1)如果正则表达式中有修饰符 ”g”, 这时,在 reg 中会保护 lastIndex 属性,记录下一次开始的地位,当第二次执行 test 的时候,从 lastIndex 开始检索。
2)如果正则表达式中没有修饰符 ”g”, 不会保护 lastIndex 属性,每次执行从开始地位检索
-
toString/toLocaleString
把正则表达式的内容转化成 字面量模式字符串/ 有本地特色的字符串(JS 中没成果)
var reg1 = /hello/;
console.log(reg1.toString()); // 返回 /hello/ 字符串
console.log(reg1.toLocaleString()); // 返回 /hello/ 字符串
-
valueOf
返回正则表达式自身
var reg1 = /hello/;
console.log(reg1.valueOf()); // 返回正则表达式自身
5. 正则表达式实例属性
-
lastIndex
当没设置全局匹配时,该属性值 始终为 0
设置了全局匹配时,每执行一次 exec/test 来匹配,lastIndex 就会移向匹配到的字符串的下一个地位,当指向的地位后没有能够再次匹配的字符串时,下一次执行 exec 返回 null,test 执行返回false,而后 lastIndex 归零,从字符串的结尾从新匹配一轮
能够了解成,每次正则 查找的终点 就是 lastIndex
var str = 'hello hello hello';
var reg1 = /hello/;
var reg2 = /hello/g;
console.log(reg1.lastIndex); // 0
console.log(reg1.exec(str)); // 返回第一个 hello
console.log(reg1.lastIndex); // 0
console.log(reg2.lastIndex); // 0
console.log(reg2.exec(str)); // 返回第一个 hello
console.log(reg2.lastIndex); // 5
console.log(reg2.lastIndex); // 5
console.log(reg2.exec(str)); // 返回第二个 hello
console.log(reg2.lastIndex); // 11
console.log(reg2.lastIndex); // 11
console.log(reg2.exec(str)); // 返回第三个 hello
console.log(reg2.lastIndex); // 17
console.log(reg2.exec(str)); // 返回 null
console.log(reg2.lastIndex); // 0
console.log(reg2.exec(str)); // 返回第一个 hello
-
ignoreCase、global、multiline
判断正则表达式中是否有疏忽大小写、全局匹配、多行匹配三个模式修饰符
var reg1 = /hello/igm;
console.log(reg1.ignoreCase); //true
console.log(reg1.global); //true
console.log(reg1.multiline); //true
-
source
返回 字面量模式 的正则表达式(相似于 toString)
var reg1 = /hello/igm;
console.log(reg1.source); //hello
6. 正则表达式语法 - 元字符
-
间接量字符
正则表达式中的所有字母和数字都是依照字面含意进行匹配的,Javascript 正则表达式语法也反对非字母的字符匹配,这些字符须要通过反斜线 \ 作为前缀进行本义。
字符 | 匹配 |
---|---|
字母和数字字符 | 本身 |
\o | Null 字符 |
\t | 制表符 |
\n | 换行符 |
\v | 垂直制表符 |
\f | 换页符 |
\r | 回车符 |
-
字符汇合
一个字符汇合,也叫字符组。匹配汇合中的任意一个字符。你能够应用连字符‘-’指定一个范畴
方括号用于查找某个范畴内的字符:
[abc] 查找方括号之间的任何字符
var str = 'abc qwe abd'
var reg1 = /[abc]/;// 只有蕴含有 a 或者 蕴含有 b 或者蕴含有 c 都返回为 true
console.log(reg1.test(str)); //true
[0-9] 查找任何从 0 至 9 的数字
var str = 'abc qwe abd1'
var reg1 = /[0-9]/igm;
console.log(reg1.test(str)); //true
1 一个反义或补充字符集,也叫反义字符组。也就是说,它匹配任意不在括号内的字符。你也能够通过应用连字符 ‘-‘ 指定一个范畴内的字符。
留神:^ 写在 [] 外面是反义字符组
var str = 'abc qwe abd1,2'
console.log(str);
var reg1 = /[^abc]/igm;
console.log(reg1.exec(str)); //true
-
边界符
^ 匹配输出开始。示意匹配行首的文本(以谁开始)。如果多行(multiline)标记被设为 true,该字符也会匹配一个断行(line break)符后的开始处。
$ 匹配输出结尾。示意匹配行尾的文本(以谁完结)。如果多行(multiline)标记被设为 true,该字符也会匹配一个断行(line break)符的前的结尾处。
如果 ^ 和 $ 在一起,示意必须是准确匹配。
var rg = /abc/;
// /abc/ 只有蕴含有 abc 这个字符串返回的都是 true
console.log(rg.test('abc')); //true
console.log(rg.test('abcd')); //true
console.log(rg.test('aabcd'));//true
console.log('---------------------------');
// 必须是以 abc 结尾的字符串才会满足
var reg = /^abc/;
console.log(reg.test('abc')); // true
console.log(reg.test('abcd')); // true
console.log(reg.test('aabcd')); // false
console.log('---------------------------');
// 必须是以 abc 结尾的字符串才会满足
var reg = /abc$/;
console.log(reg.test('abc')); // true
console.log(reg.test('qweabc')); // true
console.log(reg.test('aabcd')); // false
console.log('---------------------------');
var reg1 = /^abc$/; // 准确匹配 要求必须是 abc 字符串才符合规范
console.log(reg1.test('abc')); // true
console.log(reg1.test('abcd')); // false
console.log(reg1.test('aabcd')); // false
console.log(reg1.test('abcabc')); // false
-
字符汇合与 ”^” 和 ”$” 一起应用
// 三选一 只有是 a 或者是 b 或者是 c 这三个字母才返回 true
var rg1 = /^[abc]$/;
console.log(rg1.test('aa'));//false
console.log(rg1.test('a'));//true
console.log(rg1.test('b'));//true
console.log(rg1.test('c'));//true
console.log(rg1.test('abc'));//false
//26 个英文字母任何一个字母返回 true - 示意的是 a 到 z 的范畴
var reg = /^[a-z]$/
console.log(reg.test('a'));//true
console.log(reg.test('z'));//true
console.log(reg.test('A'));//false
// 字符组合
// 26 个英文字母 (大写和小写都能够) 任何一个字母返回 true
var reg1 = /^[a-zA-Z0-9]$/;
// 取反 方括号外部加上 ^ 示意取反,只有蕴含方括号内的字符,都返回 false。var reg2 = /^[^a-zA-Z0-9]$/;
console.log(reg2.test('a'));//false
console.log(reg2.test('B'));//false
console.log(reg2.test(8));//false
console.log(reg2.test('!'));//true
\b 匹配一个零宽单词边界(zero-width word boundary),示意一个单词(而非字符)边界,也就是单词和空格之间的地位,或者字符(\w)与字符串结尾或者结尾之间的地位。
\B 匹配一个零宽非单词边界(zero-width non-word boundary),与 ”\b” 相同。
var str = 'Hello World Hello JavaScript';
var reg1 = /\bHello\b/g;
var reg2 = /\BScrip\B/g;
console.log(reg1.exec(str));
console.log(reg2.exec(str));
-
字符类
将间接量字符独自放进方括号内就组成了字符类,一个字符类能够匹配它所蕴含的任意字符。例如:/[abc]/ 就和字母 ”a”、”b”、”c” 中的任意一个都匹配。”^” 符号用来定义否定字符类,例如:/2/ 匹配的是 ”a”、”b”、”c” 之外的所有字符。字符类能够应用连字符来示意字符范畴,例如:/[a-z]/,要匹配拉丁字母表中任何字母和数字,[a-zA-Z0-9]
字符类 | 含意 |
---|---|
. | 匹配除换行符 \n 和回车符之外的任何单个字符,等效于3 |
\d | 匹配一个数字字符,等效于[0-9] |
\D | 4 |
\w | 匹配包含下划线的任何单个字符,包含 A~Z,a~z,0~9 和下划线“_”,等效于 [a-zA-Z0-9_] |
\W | 5 |
\s | 匹配任何 Unicode 空白字符,包含空格、制表符、换页符等,等效于[\f\t\n\r] |
\S | 6 |
联合英文原意记忆:
d ==> digit(数字)
s ==> space(空白)
w ==> word(单词)
“.” 除换行符 \n 和回车符之外的任何单个字符
var str = '\nHello World Hello\r JavaScript';
console.log(str);
var reg1 = /./g;
console.log(reg1.exec(str));
\d 匹配一个数字字符,等效于[0-9]
// 以数字结尾
var str = '123Hello World Hello 123JavaScript';
console.log(str);
var reg1 = /^\d/g;
console.log(reg1.exec(str));
\D 等效于 [0-9]取反
// 不以数组结尾
var str = 'Hello World Hello 123JavaScript';
console.log(str);
var reg1 = /^\D/g;
console.log(reg1.exec(str));
\w 匹配包含下划线的任何单个字符,包含 A~Z,a~z,0~9 和下划线“_”,等效于[a-zA-Z0-9_]
\W 5
var str = '!Hello World Hello JavaScript';
// \w -> [a-zA-Z0-9_]
var reg1 = /^\w/;
console.log(reg1.test(str));
// \W -> [^a-zA-Z0-9_]
var reg2 = /^\W/;
console.log(reg2.test(str));
\s 匹配任何 Unicode 空白字符,包含空格、制表符、换页符等,等效于[\f\t\n\r]
// 以空白字符结尾
var str = '\nHello World Hello 123JavaScript';
console.log(str);
var reg1 = /^\s/g;
console.log(reg1.exec(str));
\S 等效于7
// 不以空白字符结尾
var str = 'Hello World Hello 123JavaScript';
console.log(str);
var reg1 = /^\S/g;
console.log(reg1.exec(str));
7. 数量词
字符 | 含意 |
---|---|
* | >= 0 次 |
+ | ≥1 次 |
? | 0 或 1 次 |
{n} | n 次 |
{n,} | ≥n 次 |
{n,m} | n 到 m 次 |
-
X* 匹配后面的模式 x -> 0 或屡次。等价于{0,}
// * 容许呈现 0 次或屡次
var reg = new RegExp(/^a*$/);
console.log(reg.test("a")); // true
console.log(reg.test("")); // true
-
X+ 匹配后面的模式 x -> 1 或屡次。等价于 {1,}。
// + 容许呈现 1 次或屡次
var reg2 = new RegExp(/^a+$/);
console.log(reg2.test("a")); // true
console.log(reg2.test("")); // false
-
X? 匹配后面的模式 x -> 0 或 1 次。等价于{0,1}
// ? 只容许 a 呈现 1 次或 0 次
var reg3 = new RegExp(/^a?$/);
console.log(reg3.test("a")); // true
console.log(reg3.test("")); // true
console.log(reg3.test("aaa")); // false
-
X{n} n 为非负整数。后面的模式 x 反复呈现 n 次时匹配
// {3} 容许反复 3 次
var reg4 = new RegExp(/^a{3}$/);
console.log(reg4.test("a")); // false
console.log(reg4.test("")); // false
console.log(reg4.test("aaa")); // true
console.log(reg4.test("aaaa")); // false
-
X{n,} n 为非负整数。后面的模式 x 反复呈现至多 n 次时匹配。
// {3,} 容许反复呈现 3 次或 3 次以上屡次
var reg5 = new RegExp(/^a{3,}$/);
console.log(reg5.test("a")); // false
console.log(reg5.test("")); // false
console.log(reg5.test("aaa")); // true
console.log(reg5.test("aaaa")); // true
-
X{n,m} n 和 m 为非负整数。后面的模式 x 反复呈现至多 n 次,至少 m 次时匹配。
// {3,6} 容许反复呈现 3 次 - 6 次之间,也就是 >= 3 且 <=6
var reg6 = new RegExp(/^a{3,6}$/);
console.log(reg6.test("a")); // false
console.log(reg6.test("aaaa")); // true
console.log(reg6.test("aaaaaa")); // true
console.log(reg6.test("aaaaaaa")); // false
案例
1. 匹配 QQ 号
// 不能以数字 0 开始,只能由数字组成,长度为 5 -11 位
var reg = /^[1-9]\d{4,10}$/;
var str1 = "12311111111";
var result1 = reg.exec(str1);
console.log(result1);
2. 匹配身份证号
// 不能以数字 0 结尾,只能由数字组成,最初一位可能是 x,X,数字
var reg = /^[1-9]\d{16}[xX\d]$/;
var str = "456337189654326541";
var result = reg.exec(str);
console.log(result);
反复形式
1)贪心模式:尽可能多的匹配(首先取最多可匹配的数量为一组进行匹配),当匹配残余的字符串,还会持续尝试新的匹配,直到匹配不到为止,为默认模式。
// 对字符串 "123456789",匹配其中的数字 3 - 6 次:\d{3,6},先匹配数字呈现 6 次的字符串(123456),而后再从残余字符串(789)中匹配呈现数字 3 次的状况,残余字符若没有呈现数字 3 次则进行匹配.
var str = "123456789";
var reg = /\d{3,6}/g;
console.log(reg.exec(str)); //['123456', index: 0, input: '12345678', groups: undefined]
console.log(reg.exec(str)); // ['789', index: 6, input: '123456789', groups: undefined]
console.log(reg.exec(str)); // null
2)非贪心模式:尽可能少的匹配(每次取起码匹配的数量为一组进行匹配),直到匹配不到为止
应用办法:在量词后加上 ?
// 对字符串 "123456789",匹配其中的数字 3 - 6 次:\d{3,6},先匹配数字呈现 3 次的字符串(123),而后再从残余字符串(456789)中匹配呈现数字 3 次的状况,残余字符若没有呈现数字 3 次则进行匹配.
var str = "123456789";
var reg = /\d{3,6}?/g;
console.log(reg.exec(str)); //['123', index: 0, input: '123456789', groups: undefined]
console.log(reg.exec(str)); // ['456', index: 3, input: '123456789', groups: undefined]
console.log(reg.exec(str)); // ['789', index: 6, input: '123456789', groups: undefined]
8. 抉择,分组,援用
-
抉择
字符 ”|” 用于分隔供选择的字符,选择项的尝试匹配秩序是从左到右,直到发现了匹配项,如果右边的选择项匹配,就疏忽左边的匹配项,即便它能够产生更好的匹配。
var reg = /html|css|js/
console.log(reg.exec('qweqwehtmlcss')); // html
-
分组
上面的正则表达式能够匹配 ’briupbriupbriup’
/briupbriupbriup/
而另一种更优雅的写法是:
/(briup){3}/
这里有圆括号包裹的一个小整体成为分组。
候选
一个分组中,能够有多个候选表达式,用 | 分隔:
var reg = /I Like (basketball|football|table tennis)/
console.log(reg.test('I Like basketball')); //true
console.log(reg.test('I Like football')); //true
console.log(reg.test('I Like table tennis')); //true
捕捉与援用
被正则表达式匹配(捕捉)到的字符串会被暂存起来。其中,由分组捕捉的串会从 1 开始编号,于是咱们能够援用这些串:
var reg = /(\d{4})-(\d{2})-(\d{2})/
var date = '2021-08-29'
reg.test(date)
// 捕捉之前要先 test/exec
console.log(RegExp.$1); //2021
console.log(RegExp.$2); //08
console.log(RegExp.$3); //29
$1 援用了第一个被捕捉的串,$2 是第二个,顺次类推。
嵌套分组的捕捉
如果碰到相似 /((apple) is (a (fruit)))/ 的嵌套分组,捕捉的程序是什么?
var reg = /((apple) is (a (fruit)))/
var str = "apple is a fruit"
reg.test(str) // true
RegExp.$1 // apple is a fruit
RegExp.$2 // apple
RegExp.$3 // a fruit
RegExp.$4 // fruit
规定是以左括号呈现的程序进行捕捉。
-
援用
正则表达式里也能进行援用,这称为反向援用:
var reg = /(\w{3}) is \1/
console.log(reg.test('kid is kid')); // true
console.log(reg.test('dik is dik')); // true
console.log(reg.test('kid is dik')); // false
console.log(reg.test('dik is kid')); // false
\1 援用了第一个被分组所捕捉的串,换言之,表达式是动静决定的。
留神,如果编号越界了,则会被当成一般的表达式:
var reg = /(\w{3}) is \6/;
reg.test('kid is kid'); // false
reg.test('kid is \6'); // true
9.String 对正则表达式的反对
-
search
查找字符串中是否有匹配正则的字符串,有则返回字符串 第一次呈现时的地位,无则返回null
正则中无论是否有全局匹配都 不会影响返回后果
var str = 'hello world hello';
var reg = /hello/;
var reg2 = /hello/g;
console.log(str.search(reg)); // 返回 0
console.log(str.search(reg2));// 返回 0
-
match
匹配字符串中合乎正则表达式的字符串,并返回该字符串的一个 数组 ,其中包含字符串 内容 、 地位
如果正则设置全局匹配,则 一次性返回所有 合乎正则表达式的字符串数组
如果其中增加了分组,返回符合要求的字符串以及 分组 的一个数组,但如果同时开启全局匹配则 不会在数组中增加分组内容
var str = 'hello world hello';
var reg1 = /hello/;
var reg2 = /hello/g;
var reg3 = /(he)llo/;
var reg4 = /(he)llo/g;
// 匹配字符串中合乎正则表达式的字符串,并返回该字符串的一个数组,其中包含字符串内容、地位
// ['hello', index: 0, input: 'hello world hello', groups: undefined]
console.log(str.match(reg1));
// 如果正则设置全局匹配,则一次性返回所有合乎正则表达式的字符串数组
// ['hello', 'hello']
console.log(str.match(reg2));
// 如果其中增加了分组,返回符合要求的字符串以及分组的一个数组
// [
// 'hello',
// 'he',
// index: 0,
// input: 'hello world hello',
// groups: undefined
// ]
console.log(str.match(reg3));
// 如果同时开启全局匹配则不会在数组中增加分组内容
// ['hello', 'hello']
console.log(str.match(reg4));
-
split
// 以某种模式宰割字符串 split()
var str = "terry134briup156lisi12zhangsan";
// 当数字呈现一次或屡次时
var reg = /\d+/;
var result = str.split(reg);
console.log(result); // ['terry', 'briup', 'lisi', 'zhangsan']
-
replace
// 满足正则表达式条件的内容将被替换
var str = 'javascript'
// 如果开启全局模式 则替换所有满足条件的字符
var reg = /javascript/;
// replace(正则表达式, 要替换的内容)
var result = str.replace(reg, 'java');
console.log(result); //java
console.log(str); //javascript
10. 前瞻表达式
在正则表达式当中有个货色叫做 前瞻,有的管它叫 零宽断言:
表达式 | 名称 | 形容 |
---|---|---|
(?=exp) | 正向前瞻 | 匹配前面满足表达式 exp 的地位 |
(?!exp) | 负向前瞻 | 匹配前面不满足表达式 exp 的地位 |
因为 JS 原生不反对后瞻,所以这里就不钻研它了。咱们来看看前瞻的作用:
var str = 'Hello, Hi, I am Hilary.';
// 前面肯定要匹配什么
var reg = /H(?=i)/g;
var newStr = str.replace(reg, "T");
console.log(newStr);//Hello, Ti, I am Tilary.
在这个 DEMO 中咱们能够看出正向前瞻的作用,同样是字符 ”H”,然而只匹配 ”H” 前面紧跟 ”i” 的 ”H”。就相当于有一家公司 reg,这时候有多名 ”H” 人员前来应聘,然而 reg 公司提出了一个硬条件是必须把握 ”i” 这项技能,所以 ”Hello” 就天然的被淘汰掉了。
那么负向前瞻呢?情理是雷同的:
var str = 'Hello, Hi, I am Hilary.';
// 前面肯定不要匹配什么
var reg = /H(?!i)/g;
var newStr = str.replace(reg, "T");
console.log(newStr);//Tello, Hi, I am Hilary.
在这个 DEMO 中,咱们把之前的正向前瞻换成了负向前瞻。这个正则的意思就是,匹配 ”H”, 且前面不能跟着一个 ”i”。这时候 ”Hello” 就能够胜利的应聘了,因为 reg 公司批改了他们的招聘条件,他们说 ”i” 这门技术会有损公司的企业文化,所以咱们不要了。
- xyz ↩
- abc ↩
- \n\r ↩
- 0-9 ↩
- a-zA-Z0-9_ ↩
- \f\t\n\r ↩
- \f\t\n\r ↩