JS-正则表达式

240 阅读1分钟

正则表达式(regular expression),用来匹配字符串的一种规则,常用来匹配、检查、替换字符。在 JavaScript 中可以长成像这样: /^[a-z0-9]+$/i ,它可以作为程序执行表达式的一部分,也可以在具备正则能力的工具里利用它,比如在 VSCode 的搜索里面用它来花式匹配、替换代码等。

正则表达式

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

例如/apple/i就代表了一个正则表达式,它的含义是匹配字符串中的“apple”字符,并且不区分大小写。

配合 String.prototype.replace 方法,我们可以用正则表达式来替换字符串中的内容。试着将字符串中的“apple”替换成“orange”:

const str = "Apple is red";
const reg = /apple/i;

const newStr = str.replace(reg, "Orange");

console.log(newStr); // "Orange is red"

创建正则表达式

字面量

最简单的方式是使用格式为/ *表达式主体* / *标志*这样的字面量来创建:

const reg = /^[a-z0-9]+$/i;

RegExp 对象

还可以调用RegExp对象的构造函数创建一个正则表达式对象:

const reg = new RegExp("^[a-z0-9]+$", "i");

正则表达式语法

从简单到复杂

一个表达式可能只是一个简单的字符匹配,也有可能是一个复杂的组合表达式。从匹配到组合的过程中,我们可以通过添加更多的条件来提高匹配的效率。

想要更灵活和高效就需要了解更多的规则,只要从匹配的**字符数量位置**三个方面入手,基本就可以掌控它。

字符

普通字符

正则表达式可以就好像我们开头说的“apple”一样,精确匹配想要的某几个普通字符。

特殊含义字符

有一些特定的字符或者字符组在正则表达式中是有特殊含义的。例如 \ 特殊含义是转义字符,跟在它后面的字符不再是普通字符,而是和\组成了一个特殊含义的标识,这个标识可能代表了一类字符。

如果遇见前面不是\,但是它却是特殊含义的字符时,想要获得它对应的普通字符匹配时,就需要在前面加上一个\。也就是如果要匹配\原本的“\”普通字符该怎么办?在它前面再加个转义符\就好了,/\\/就代表去匹配“\”。

字符含义
.默认匹配除换行符之外的任何单个字符;如果修饰符的 s 开启的话,它也会匹配换行符
\w匹配一个单字字符(字母、数字或者下划线)。等价于 [A-Za-z0-9_]
\W取反\w,等价于 [^A-Za-z0-9_]
\d匹配一个数字,等价于 [0-9]
\D取反\d,等价于 [^0-9]
\s匹配一个空白字符,包括空格、制表符、换页符和换行符
\S取反\s
\n匹配一个换行符 (U+000A)
\r匹配一个回车符 (U+000D)
\f匹配一个换页符 (U+000C)
\t匹配一个水平制表符 (U+0009)
\v匹配一个垂直制表符 (U+000B)
\0匹配 NULL(U+0000)字符, 不要在这后面跟其它小数,因为 \0 是一个八进制转义序列
\xhh匹配一个两位十六进制数(\x00-\xFF)表示的字符
\uhhhh匹配一个四位十六进制数表示的 UTF-16 代码单元
\u{hhhh}\u{hhhhh}(仅当设置了 u 标志时)匹配一个十六进制数表示的 Unicode 字符

范围性匹配

针对需要将字符限定在一定范围内的情况,有如下规则:

字符含义
x|y匹配‘x’或者‘y’
[xyz]一个字符集合。匹配方括号中的任意字符,包括转义序列
[^xyz]取反 [xyz]
[a-z]匹配字母 a 到 z
[0-9]匹配数字 0 到 9

数量

贪婪

正则中有一些字符是用来限定字符出现的次数的。要注意像 * 和 + 这样的量词是“贪婪的”,这意味着它们试图匹配尽可能多的字符串。

字符含义
*前面的字符出现 >=0 次
+前面的字符出现 >=1 次
?前面的字符出现 0 或 1 次
{n}前面的字符出现 n 次, n 是一个正整数
{n,}前面的字符出现 >=n 次, n 是一个正整数
{n,m}前面的字符出现 n至m 次,n 和 m 都是整数

惰性

想要控制匹配不贪婪,需要再加一些限定。?量词后面的字符使量词“非贪婪”:意思是它一旦找到匹配就会停止。

有一段字符串 "okokook",分别用两个表达式匹配看一下结果:

  1. /o.*k/ 结果是 "okokook" => 贪婪
  2. /o.*?k/ 结果是 "ok" => 惰性

位置

边界定位

^$是边界定位符,它们可以用来限定匹配的字符串必须以某个字符开头或者结尾。

字符含义
^匹配输入的开始。如果多行标志被设置为 true,那么也匹配换行符后紧跟的位置。
$匹配输入的结束。如果多行标志被设置为 true,那么也匹配换行符前的位置。
\b匹配单词边界
\B匹配非单词边界

关于\b
匹配一个词的边界。一个词的边界就是一个词不被另外一个“字”字符跟随的位置或者前面跟其他“字”字符的位置,例如在字母和空格之间。注意,匹配中不包括匹配的字边界。换句话说,一个匹配的词的边界的内容的长度是 0。(不要和[\b]混淆了)

使用"moon"举例:
/\bm/匹配“moon”中的‘m’;
/oo\b/并不匹配"moon"中的'oo',因为'oo'被一个“字”字符'n'紧跟着。
/oon\b/匹配"moon"中的'oon',因为'oon'是这个字符串的结束部分。这样他没有被一个“字”字符紧跟着。
/\w\b\w/将不能匹配任何字符串,因为在一个单词中间的字符永远也不可能同时满足没有“字”字符跟随和有“字”字符跟随两种情况。

关于\b
匹配一个非单词边界。匹配如下几种情况:

  • 字符串第一个字符为非“字”字符
  • 字符串最后一个字符为非“字”字符
  • 两个单词字符之间
  • 两个非单词字符之间
  • 空字符串

例如,/\B../匹配"noonday"中的'oo', 而/y\B../匹配"possibly yesterday"中的’yes‘

位置关系

当存在需要查找某段字符前面或后面的字符的情况,可能需要使用下面的规则:

请注意以下 exp2 表示与 exp1 存在位置关系的表达式, exp1 才是目标表达式

字符含义
exp1(?=exp2)匹配后面是 exp2 的 exp1
exp1(?!exp2)匹配后面不是 exp2 的 exp1
(?<=exp2)exp1匹配前面是 exp2 的 exp1
(?<!exp2)exp1匹配前面不是 exp2 的 exp1

组及相关

字符含义
(x)捕获组
\n其中 n 是一个正整数。对正则表达式中与 n 括号匹配的最后一个子字符串的反向引用(计算左括号)
(?<Name>x)具名捕获组: 匹配"x"并将其存储在返回的匹配项的 groups 属性中,该属性位于指定的名称下。尖括号(< 和 >) 用于组名
(?:x)非捕获组: 匹配 “x”,但不记得匹配

关于组的细节请参考MDN Groups and ranges

修饰符

正则表达式有六个可选参数 (flags) 允许全局和不分大小写搜索等。这些参数既可以单独使用也能以任意顺序一起使用, 并且被包含在正则表达式实例中。

标志含义
i全局搜索。
m不区分大小写搜索。
g多行搜索。
s允许 . 匹配换行符。
u使用 unicode 码的模式进行匹配。
y执行“粘性(sticky)”搜索,匹配从目标字符串的当前位置开始。

Unicode 属性转义

请参考 MDN Unicode 属性转义

常用正则表达式

用途正则表达式
vscode 匹配一般 console.log(?<!=>\s)(\/\/?\s*)?console.log\((.*)\);?
vscode 匹配一般空行^\s*(?=\r?$)\n

可参考第三方开源整理库 any86.github.io/any-rule/

参考