Skip to content

正则对象

正则表达式又称规则表达式(Regular Expression)。
RegExp。常用于检索匹配替换符合规则的文本。
JavaScript 对他进行了本地化实现。
正则表达式是对字符串的操作逻辑匹配,可以匹配一个或者多个字符串
正则表达式又多个核心的功能: 匹配是否满足条件,获取想要的部分
JavaScript 中正则对象的字面量写法是/原始正则表达式/
生成正则表达式的方式:

javascript
let reg1 = /asd/g //字面量写法,g是修饰符
let reg2 = new RegExp(/asd/g) //也是字面量写法
let reg3 = new RegExp("asd", "g") //匹配方法 匹配模式(修饰符)

相关方法

正则表达式是一个对象,具有testexec方法,
test是测试前面的正则表达式在后面找得到,就返回true,否则就返回false

javascript
typeof /asd/ //object
;
/as/.test("asd") //true
;
/asd/.test("assd") //false

exec中匹配到了就会返回一个数组:

javascript
;
/asd/.exec("asd") //["asd", index: 0, input: "asd", groups: undefined]
;
/asd/.exec("assd") //null

数组对象中第一项是第一个满足匹配的字符串,第二项的是满足匹配开始的下标。第三项是被匹配的输入。groups是命名捕获组。
字符串String具有

  • match
  • replace
  • search
  • split
javascript
> "asd".match("as");
["as", index: 0, input: "asd", groups: undefined] >
"asd".match(/as/);
["as", index: 0, input: "asd", groups: undefined]
//没有就是null

>
"asd".replace(/as/, "sa");
"sad"
//不会改变原字符串,没匹配就不变

>
"asd".search(/dd/); -
1
    //返回第一个匹配的位置下标,没有就-1
    >
    "asd".search(/sd/);
1
    >
    "asd".split(/s/);
["a", "d"];

修饰符

JavaScript 中,正则表达式的字面量具备修饰符 igmu
修饰符是写到正则匹配的第二个斜杠后面,表示前面的表达式匹配的一些设置

i 对大小写不敏感,可以无视大小写匹配

javascript
> /a/i.test("AAA");
true
    >
    /a/.test("AAA");
false

g 全局匹配,不在第一次匹配后停止,继续向后匹配

javascript
> "asdaassddaaddss".match(/aa/);
["aa", index: 3, input: "asdaassddaaddss", groups: undefined] > //只匹配到了第一个。
undefined

    >
    "asdaassddaaddss".match(/aa/g);
["aa", "aa"]

m 多行匹配,将具有换行的字符串(\n)每行单独匹配

javascript
"asd\nasdf".match(/d$/gm) //["d"];
"asd\nasdf".match(/d$/g) //null;

u unicode 匹配模式,能识别 unicode 标识符。{}前面必须加上\u 表示识别 unicode 编码

javascript
;
/\u{61}/.test("a") //false
;
/u{61}/u.test("a") //false
;
/\u{61}/u.test("a") //true

元字符

正则表达式的特殊字符

\ 转义字符,将特殊字符转换成普通字符 比如 new RegExp(/\//)

javascript
;
/\\/.test("d") //false,前面是匹配没有转义的\ 后面的\d被转义了
;
/\\/.test("\\d") //true,前面是匹配没有转义的\ 后面的\d没有转义

\w 单个任意普通字符,等价于[0-9A-z_]

javascript
"fsd".match(/\w/) //["f", index: 0, input: "fsd", groups: undefined]

\W 单个任意非字符,等价于[^0-9A-z_]

\d 任意单个数值,等价于[0-9]

\D 任意单个非数值,等价于[^\d]

\s 任意空格的内容,等价于[\t\n\r\v\f ],包含了空格和等价于空格的内容(空格 制表符 回车 换行 垂直换行 换页)

\S 等价于[^\s]

\b 匹配单词边界的位置

javascript
"abfd fgh jkl".match(/\bf/) //["f", index: 5, input: "abfd fgh jkl", groups: undefined]
"abfd fgh jkl".match(/h\b/) //["h", index: 7, input: "abfd fgh jkl", groups: undefined]

此时 fgh 的 f 在单词边界,所以满足匹配

\B 匹配非单词边界

^ 匹配开始输入是不是相关字符

javascript
;
/^asd/.test("asmdasd") //false
;
/^asd/.test("asdqwe") //true

$ 匹配是不是以相关字符结束

javascript
;
/asd$/.test("qwerasd") //true
;
/^a$/.test("aaa") //false
;
/^a$/.test("a") //true   以a开始并且以这个a结束
;
/^aa$/.test("aasa") //true

量词

{a,b} 匹配前面的字符最少 a 次最多 b 次

{a} 匹配前面的字符 a 次,不多不少

{a,} 匹配前面的字符至少 a 次,可多

javascript
"asasssassdd".match(/as{1,3}/g) //["as", "asss", "ass"]
"asasssassdd".match(/as{3}/g) //["asss"]

* 匹配前面的字符 0 次或多次

​ 等价于{0,}

javascript
"asasd".match(/a*/) //["a", index: 0, input: "asdasd", groups: undefined]
"asdasd".match(/b*/) //["", index: 0, input: "asdasd", groups: undefined] 匹配了0次

+ 匹配前面的字符 1 次或多次

​ 等价于{1,}

javascript
"asdasd".match(/b+/g) //null
"asdaasd".match(/a+/g) //["a", "aa"]

? 匹配前面的字符 0 次或 1 次

​ 等价于{0,1}

javascript
"aassddasdf".match(/da?/g) //["d", "da", "d"]
"nice! nice to meet you".match(/nice!?/g) //["nice!", "nice"]
  • 惰性匹配

    我们发现,当量词数量不唯一的时候,正则匹配会默认以贪心模式匹配。尽可能匹配多的元素

    javascript
    "haaaaaaaahaaahaaha".match(/ha+/g) //["haaaaaaaa", "haaa", "haa", "ha"]

    在量词后面添加惰性量词,他就会尽可能匹配少的元素

    javascript
    "haaaaaaaahaaahaaha".match(/ha+?/g) //["ha", "ha", "ha", "ha"]
    "ha??? who??? are you??".match(/a\???/g) //?转义 a后面的"?"有{0,1}但是尽可能少的匹配
  • 字母和数值以及范围: [a-z]等

    [a-z]等价于

javascript
"asd123asd".match(/[a-d]/g) //["a", "d", "a", "d"] a,b,c,d
"asd123asd".match(/[a-zA-Z]/g) //["a", "s", "d", "a", "s", "d"]
//匹配字母,等同于下面,不区分大小写

[0-9]等价于

javascript
"asd123asd".match(/[0-9]/g) //["1", "2", "3"]
//数值等价于\d
"asd123asd".match(/\d/g) //["1", "2", "3"]
"Asd123asd".match(/^[a-z]/gi) //["A"]
"asdfghjkl".match(/[^asd]/g) //["f", "g", "h", "j", "k", "l"]

[^xyz]反向匹配,不是范围内的元素

javascript
"Asd123asd".match(/[^a-z]/gi) //["1", "2", "3"]

[\u4e00-\u9fa5],任意汉字

javascript
"大as家12 3_?好!".match(/[\u4e00-\u9fa5]/) //["大", "家", "好"]

分组

js 不支持命名分组,固化分组。

  • (...) 匹配并获取匹配(pattern),获取支持 replace 第二个参数"$1" "$2"

    通常用于 replace 时,第二个参数可以用$1 $2来指代你获取的元素,方便替换

    (?:...) 可以分组不获取匹配

javascript
//将任意中文后面的全角"!"替换成英文的"!"
>
"你好啊!我很高兴!asd!".replace(/([\u4e00-\u9fa5])!/g, "$1!")
"你好啊!我很高兴!asd!"

事实上,replace 可以接受函数,函数的形参指代被匹配的字符串:

javascript
//2048游戏合并单行
function foo(arr) {
    const s = arr.filter((v) => v !== 0).join(",")
    return (s.replace(/(\d+),\1/g, (w) => w[0] << 1) + ",0,0,0,0")
        .split(",")
        .map((v) => 1 * v)
        .slice(0, 4)
}

console.log(foo([64, 128, 2, 2]))
  • (|)与[]中的|等价。从左往右只要有一个满足任意条件即匹配

重复出现

\1 前一个分组多重复一次

\1\1 前一个分组重复 3 次

(\d)\1{2} 一个数字重复 3 次

断言

匹配某个字符串,前提是前面或者后面必须满足条件(?),都为非获取

  • ​ (?=pattern) 正向肯定,如果后面有,那么匹配成功
  • ​ (?!pattern) 正向否定,如果后面没有,那么匹配成功
javascript
"asd123asd12".match(/asd(?!123)/g) //["asd"] 这是第二个asd
"asd123asd12".match(/asd(?=123)/g) //["asd"] 这是第二个asd
;
`asd123
Asd123
aSd321`.match(/^(?!Asd).*/gm) //匹配不以Asd开头的行["asd123", "aSd321"]
  • ​ (?<=pattern) 反向肯定,如果前面有,那么匹配成功,要写到前面
javascript
"asdd123asd12".match(/(?<=123)asd/g) //匹配前面有123的asd,也就是第二个["asd"]
  • ​ (?<!pattern) 反向否等,如果前面没有,那么匹配成功
javascript
"book.js,book1.js,book.css".match(/(?<!book)\.js/g) //匹配第二个js

很多书本上,断言也叫做环视、预查。