乐趣区

关于javascript:正则表达式

正则表达式

正则表达式(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” 这门技术会有损公司的企业文化,所以咱们不要了。


  1. xyz ↩
  2. abc ↩
  3. \n\r ↩
  4. 0-9 ↩
  5. a-zA-Z0-9_ ↩
  6. \f\t\n\r ↩
  7. \f\t\n\r ↩
退出移动版