第15章 正则表达式

740 阅读5分钟

正则表达式可视化工具 >>

一、概述

正则表达式(Regular_Expressions)用于匹配字符串中字符组合的模式。在 JavaScript中,正则表达式也是对象。这些模式被用于 RegExpexectest 方法, 以及 StringmatchmatchAllreplacesearchsplit 方法。

简单的说,就是按照某种规则去匹配符合条件的字符串。

二、创建正则表达式

新建正则表达式有两种方法。一种是使用字面量,以斜杠表示开始和结束;另一种是使用RegExp构造函数。

// 1、使用字面量:编译时创建
var r1 = /CHINA/;

// 2、使用RegExp构造函数:运行时创建
var r2 = new RegExp("CHINA");

正则表达式还可以接受第二个参数,表示修饰符(详细解释见下文)。

var r1 = /CHINA/i;
var r2 = new RegExp("CHINA", "i");

正则对象生成以后,有两种使用方式:

  • 正则对象的方法:将字符串作为参数,比如 regex.test(string)
  • 字符串对象的方法:将正则对象作为参数,比如 string.match(regex)

三、正则属性和方法

1、属性

正则对象的属性分成两类。

一类是修饰符相关,返回一个布尔值,表示对应的修饰符是否设置,ES6新增了y 修饰符与u修饰符。

  • ignoreCase:返回一个布尔值,表示是否设置了i修饰符,用于 忽略大小写 ,该属性只读。
  • global:返回一个布尔值,表示是否设置了g修饰符,用于 全局匹配 ,该属性只读。
  • multiline:返回一个布尔值,表示是否设置了m修饰符,用于 多行模式匹配 ,该属性只读。
var r = /abc/igm;

r.ignoreCase // true
r.global     // true
r.multiline  // true

另一类是与修饰符无关的属性,主要是下面两个。

  • lastIndex:返回下一次开始搜索的位置。该属性可读写,但是只在设置了 g 修饰符时有意义。
  • source:返回正则表达式的字符串形式(不包括反斜杠),该属性只读。

2、方法

2.1、test() *

正则对象的test方法返回一个布尔值,表示当前模式是否能匹配参数字符串。

// 1、检测字符串是否包含‘@’
/@/.test('lihy_online@163.com'); // true

// 2、检测字符串是否包含‘@’
/@/.test("Nothing's gonna change my love for you.") // false

如果正则表达式带有g 修饰符,则每一次test方法都从上一次结束的位置开始向后匹配。

var reg = /n/g;

reg.lastIndex
0
reg.test("morning");
true
reg.lastIndex
4
reg.test("morning");
true
reg.lastIndex
6
reg.test("morning");
false
reg.lastIndex
0

上面代码的正则对象使用了 g 修饰符,表示要记录搜索位置。接着,三次使用test方法,每一次开始搜索的位置都是上一次匹配的后一个位置。带有 g 修饰符时,可以通过正则对象的 lastIndex 属性指定开始搜索的位置。

var reg = /n/g;

reg.lastIndex = 6;
reg.test("morning");

false

上面代码指定从字符串的第6个位置开始搜索,这个位置后面是没有字符 n 的,所以返回 false

lastIndex 属性只对同一个正则表达式有效,所以下面这样写是错误的。

var count = 0;
while (/a/g.test('blablabla')) { 
  count++;
}

上面代码会导致无限循环,因为 while 循环的每次匹配条件都是一个新的正则表达式,导致 lastIndex 属性总是等于0。

如果正则模式是一个空字符串,则匹配所有字符串。

new RegExp('').test('abc') // true

2.2、exec()

正则对象的 exec 方法,可以返回匹配结果。如果发现匹配,就返回一个数组,成员是每一个匹配成功的子字符串,否则返回 null

请看示例:

reg_exec.png

四、字符串对象的方法

字符串对象的方法之中,有4种与正则对象有关。

  • match():返回一个数组,成员是所有匹配的子字符串。

    "Hello".match(/l/g);
    (2) ['l', 'l']
    
  • search():按照给定的正则表达式进行搜索,返回一个整数,表示匹配开始的位置。

    "曾经沧海难为水,留取丹心照汗青。".search(/沧海/);
    2
    
  • replace():按照给定的正则表达式进行替换,返回替换后的字符串。

    "来咯,来咯,真嘞来咯!".replace(/来咯/, "走咯");
    "走咯,来咯,真嘞来咯!"
    
    "来咯,来咯,真嘞来咯!".replace(/来咯/g, "走咯");
    "走咯,走咯,真嘞走咯!"
    

    replace 方法的第二个参数可以使用美元符号 $ ,用来指代所替换的内容。

    • $&:指代匹配的子字符串。
    • $`:指代匹配结果前面的文本。
    • $' :指代匹配结果后面的文本。
    • $n:指代匹配成功的第n组内容,n是从1开始的自然数。
    • $$:指代美元符号*$*。
    // 1、$&:指代匹配的子字符串。
    "ABC".replace(/B/, '-$&-');
    'A-B-C'
    
    // 2、$`:指代匹配结果前面的文本。
    "ABC".replace(/B/, '$`');
    'AAC'
    
    // 3、$' :指代匹配结果后面的文本。
    "ABC".replace(/B/, "$'");
    'ACC'
    
    // 4、$n:指代匹配成功的第n组内容,n是从1开始的自然数。
    "17398888669".replace(/(\d{3})(\d{4})(\d{4})/, "$1 *** $3");
    '173 *** 8669'
    
    // 5、$$:指代美元符号$。
    "ABC".replace(/B/, "$$");
    'A$C'
    
  • split():按照给定规则进行字符串分割,返回一个数组,包含分割后的各个成员。

    "A-B-C".split('-');
    (3) ['A', 'B', 'C']
    

五、匹配规则 *

正则表达式对字符串的匹配有很复杂的规则。下面一一介绍这些规则。

01. 字面量字符

字面意义,如 /muzili/ ,匹配的就是字符串 muzili

02. 元字符

字符描述
.表示除换行、回车之外的所有字符
^表示字符串的开始位置
$表示字符串的结束位置
``选择符,如 `xy表示匹配xy ,比如:火锅烧烤` 表示匹配 火锅 或 烧烤
\转义字符,用于匹配一些特殊字符本身,比如要匹配字符+,你应该使用 \+ 表示

03. 量词符

模式的精确匹配次数,使用大括号({})表示。

字符描述
{n}表示指定字符重复n次
{n,}表示指定字符至少重复n次
{n,m}表示指定字符重复不少于n次,不多于m次
*量词符:表示某个模式出现0次或多次,等同于{0,}
+量词符:表示某个模式出现1次或多次,等同于{1,}
?量词符:表示某个模式出现0次或1次, 等同于{0,1}

04. 特殊字符

字符含义
\t水平制表符
\v垂直制表符
\n换行符
\r回车符
\0空字符
\f换页符
\cX控制字符,与X对应的控制字符(Ctrl + X)

05. 字符类

表示符合某种特性的字符类别,使用 [] 表示

字符描述
[xyz]表示匹配x、y、z中的任意一个字符
[^xyz]表示字符串中只有模式中的字符时,才返回false
[^]表示匹配任意字符
[0-9]连字符,表示匹配0~9之间的任意字符,也可用于表示字母,比如[A-Z]

tips:字符类的连字符必须在头尾两个字符中间,才有特殊含义,否则就是字面含义。比如,[-9]就表示匹配连字符和9,而不是匹配09

06. 预定义模式

预定义模式指的是某些常见模式的简写方式。

字符描述
\d匹配0-9之间的任一数字,相当于[0-9]
\D匹配所有0-9以外的字符,相当于[^0-9]
\w匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]
\W除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
\s匹配空格(包括制表符、空格符、断行符等),相等于[\t\r\n\v\f]
\S匹配非空格的字符,相当于[^\t\r\n\v\f]
\b匹配词的边界,即该次必须独立存在,如:/\bhello/.test("hello world") 为true
\B匹配非词边界,即在词的内部

07. 贪婪模式 & 非贪婪模式

  • 贪婪模式:尽可能多匹配(默认)
  • 非贪婪模式:尽可能少匹配

贪婪模式转非贪婪模式在量词符后加上即可。

/\d+/.exec("123");
// => ["123", index: 0, input: "123", groups: undefined]
/\d+?/.exec("123");
// => ["1", index: 0, input: "123", groups: undefined]

08. 修饰符

修饰符(modifier)表示模式的附加规则,放在正则模式的最尾部。

  • g:全局匹配 *
  • i:忽略大小写 *
  • m:多行模式

09. 组匹配

字符描述
(x)捕获组
模式 /(foo) (bar) \1 \2/ 中的 '(foo)' 和 '(bar)' 匹配并记住字符串 "foo bar foo bar" 中前两个单词。模式中的 \1\2 表示第一个和第二个被捕获括号匹配的子字符串,即 foobar,匹配了原字符串中的后两个单词。注意 \1\2、...、\n 是用在正则表达式的匹配环节。而在正则表达式的替换环节,则要使用像 $1$2、...、$n 这样的语法,例如,"17398888669".replace(/(\d{3})(\d{4})(\d{3})/, "$1****$3")$& 表示整个用于匹配的原字符串。
(?:x)非捕获组:表示不返回该组匹配的内容,即匹配的结果中不计入这个括号。
非捕获组的作用请考虑这样一个场景,假定需要匹配a或者aa,正则表达式就应该写成/(a){1,2}/,但是这样会占用一个组匹配。这时,就可以使用非捕获组,将正则表达式改为/(?:a){1,2}/,它的作用与前一个正则是一样的,但是不会单独输出括号内部的内容
x(?=y)先行断言:
x只有在y前面才匹配,y不会被计入返回结果。比如,要匹配后面跟着百分号的数字,可以写成/\d+(?=%)/
x(?!y)先行否定断言:
x只有不在y前面才匹配,y不会被计入返回结果。比如,要匹配后面跟的不是百分号的数字,就要写成/\d+(?!%)/

六、附:常用正则表达式

点击前往 史上最全常用正则表达式