JS基础 - 正则

正则的语法及相关 API

语法

创建

创建一个正则表达式对象有两种方式:

  1. 使用 new RegExp("pattern", "flags"),pattern 是模式,flags 是修饰符。

    例如:new RegExp('name','g')

  2. 使用斜杠语法,这种写法的缺点是他不接受变量插入

    例如:/name/g

修饰符

  • i:不区分字母的大小写

  • g:查找所有匹配项

  • m:多行模式,只会对^$造成影响

    举个例子:

    let str = `1st place: Winnie
    2nd place: Piglet
    33rd place: Eeyore`;
    
    str.match(/^\d+/g); // output: 1
    

    此时并没有输出所有数字,即使 Winnie 后的字符串进行了换行,但依然将其视作一行字符串,将正则改写成/^\d+/gm就可以正常输出结果

  • u:打开 unicode 支持(在 firefox 和 edge 中使用会有 bug)

  • y:粘滞模式

相关API

regexp.test(str)

用途:判断正则表达式与指定字符串是否匹配。

如果找到匹配项返回true,没有找到则返回false

/\d/.test('123') // output: true

regexp.exec(str)

用途:在字符串中找到匹配的字符。

如果没有找到匹配的字符,则返回null

在调用exec方法时,如果正则为全局匹配时,其返回的结果跟match方法非全局匹配下的结果一致,不过exec会维护一个lastIndex属性,当匹配到字符串时,会将lastIndex属性设置为当前匹配项的结束的位置:

let reg = /\d/g;
reg.exec('123');

// output:
// 0: "1"
// groups: undefined
// index: 0
// input: "123"

console.log(reg.lastIndex); // output: 1 

// 再次执行
reg.exec('123');

// output:
// 0: "2"
// groups: undefined
// index: 1
// input: "123"

console.log(reg.lastIndex); // output: 2

如果正则不是全局匹配,则会每一次都将 lastIndex 重置为 0 ,并重头开始查找:

let reg = /\d/;
reg.exec('123');
console.log(reg.lastIndex); // output: 1 

// 再次执行
reg.exec('123');
console.log(reg.lastIndex); // output: 1

如果在不使用全局匹配的情况向下,依然要记住上一次的 lastIndex,可以使用y修饰符:

let reg = /\d/y;
reg.exec('123');
console.log(reg.lastIndex); // output: 1 

// 再次执行
reg.exec('123');
console.log(reg.lastIndex); // output: 2

str.search(regexp)

用途:搜索一个匹配字符,返回首次匹配到的索引,如果没有找到匹配字符,则返回-1

/\d/.test('123') // output: 0

str.match(regexp)

用途:在字符串中找到匹配的字符。

如果没有找到匹配的字符,则返回null

如果正则还有全局搜索标记g,则会返回匹配倒的字符的数组:

let str = "name=nick; first_name=john"
str.match(/name=([^;]{0,})/g) 
// output: ["name=nick", "name=john"]

如果不含标记g,则会返回第一个匹配项,包含其详细信息,第一项是完全匹配的内容,后几项是与捕获括号相对应的匹配字符串

let str = "name=nick; first_name=john"
str.match(/name=([^;]{0,})/) 
// output: 
// 0: "name=nick"
// 1: "nick"
// groups: undefined
// index: 0
// input: "name=nick; first_name=john"

如果使用 index 来获取匹配项不方便,可以对捕获括号进行进行命名,在捕获括号后跟上?<name>即可对组进行命名(要注意的是IE11不支持组命名):

let str = "name=nick; first_name=john"
str.match(/name=(?<name>[^;]{0,})/)
// output:
// 0: "name=nick"
// 1: "nick"
// groups: {name: "nick"}
// index: 0
// input: "name=nick; first_name=john"

str.replace(regexp, replacement)

用途:在字符串中找到匹配的字符并使用新字符进行替换(生成新字符串,不会修改原字符串)。

有两种方式可以实现替换

一种方式是使用$n的方式对捕获组内的字符串进行替换:

let str = "nick john";
str.replace(/(\w+) (\w+)/, '$2, $1'); // output: john,nick

另一种方式是通过组名来替换,引用方式为$<name>

let str = "nick john";
str.replace(/(?<first>\w+) (?<second>\w+)/, '$<second>, $<first>'); // output: john,nick

正则符号

字符 含义
\
转译字符
常用转译:
\d:匹配一个数字,等价于[0-9]
\D:匹配一个非数字,等价于[^0-9]
\n:匹配一个换行符
\r:匹配一个回车符
\s:匹配一个空白字符
\S\s取反
\w:匹配一个单字字符(字母数字或者下划线,等价于[A-Za-z0-9_]
\W\w取反
^ 匹配输入的开始,当^出现在一个字符合集内时表示取反
$ 匹配输入的结尾
|
* 匹配前一个表达式的0次或多次,等价于{0,}
+ 匹配前一个表达式的1次或多次,等价于{1,}
? 匹配前一个表达式的0次或1次,等价于{0,1},正则默认是贪婪模式,即尽可能多的匹配,加上问号后就变成了非贪婪模式
. 匹配换行符以外的所有单个字符
(x) 捕获括号,记住匹配项,它表示一个区块,例如/foo{1,2}/{1,2}匹配的是字母o,而/(?:foo){1,2}/匹配的是整个单词foo
(?:x) 非捕获括号,不记住匹配项,匹配项不会出现在 match 方法的结果数组中
x(?=y) 先行断言,foo(?=abc)表示当 foo 后面跟着 abc 时才会才会匹配 foo
(?<=y)x 后行断言,(?<=abc)foo表示当 foo 的前面是 abc 时才会匹配 foo
注意:IE 和 safari 并不支持(兼容性
x(?!y) 正向否定查找,foo(?!abc)仅当 x 后面不跟着 abc 时才会匹配 foo
(?!y)x 反向否定查找,(?!abc)foo仅当 x 前面不跟着 abc 时才会匹配 foo
{} 匹配次数,{n}表示前面单个字符出现了 n 次,{n,}表示前面单个字符至少出现了 n 次,{n,m}表示前面单个字符出现次数大于等于 n,小于等于 m
[] 字符合集,匹配方括号中的单个任意字符,其内的特殊字符不需要转义
若用-分割,则表示一个范围,/[abcd]//[a-d]/是一样的
例如:/V[oi]la/能够匹配Vola或者Vila,单不能匹配Voila
[^] 反向字符集,[^a-d]表示匹配不含 a 到 d 的字母的字符
\b 边界,类似于^$,当遇到\b时会检查字符串位置是否处于边界
/\bJava\b/表示匹配 Java 字符串,且两遍的字符不属于\wHello,Java能够匹配,但Hello,Javascript无法匹配
\B表示非边界值

常用正则

手机号正则

/^1[3-9]\d{9}$/

身份证正则

/(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}$)/
作者

BiteByte

发布于

2021-05-19

更新于

2024-01-11

许可协议