lei4519 / blog

记录、分享
4 stars 1 forks source link

正则表达式 #51

Open lei4519 opened 7 months ago

lei4519 commented 7 months ago

模糊匹配

  1. 横向模糊匹配

    匹配的字符串长度不是固定的,使用量词实现

  2. 纵向模糊匹配

    匹配的字符不是确定的,使用字符组实现

字符组

[abc],表示匹配一个字符,它可以是 "a"、"b"、"c" 之一

  1. 范围表示法

    [a-z0-9]: 匹配 a 到 z,0 到 9 的字符

  2. 排除字符组

    使用 ^ 表示求反,[^a-z] 匹配除了 a 到 z 的字符

  3. 简写形式

字符组 具体含义
\d 表示 [0-9]。表示是一位数字。记忆方式: 其英文是 digit(数字)。
\D 表示 [^0-9]。表示除数字外的任意字符。
\w 表示 [0-9a-zA-Z_]。表示数字、大小写字母和下划线。记忆方式:w 是 word 的简写,也称单词字符。
\W 表示 [^0-9a-zA-Z_]。非单词字符。
\s 表示 [ \t\v\n\r\f]。表示空白符,包括空格、水平制表符、垂直制表符、换行符、回车符、换页 符。记忆方式:s 是 space 的首字母,空白符的单词是 white space。
\S 表示 [^ \t\v\n\r\f]。非空白符。
. 表示 [^\n\r\u2028\u2029]。通配符,表示几乎任意字符。换行符、回车符、行分隔符和段分隔符 除外。记忆方式: 想想省略号 ... 中的每个点,都可以理解成占位符,表示任何类似的东西。

量词

量词也称为重复

  1. 简写形式
量词 具体含义
{m,} 表示至少出现 m 次。
{m} 等价于 {m,m},表示出现 m 次。
? 等价于 {0,1},表示出现或者不出现。记忆方式: 问号的意思表示,有吗?
+ 等价于 {1,},表示出现至少一次。记忆方式: 加号是追加的意思,得先有一个,然后才考虑追加。
* 等价于 {0,},表示出现任意次,有可能不出现。记忆方式: 看看天上的星星,可能一颗没有,可能零散有几颗,可能数也数不过来。
  1. 惰性匹配

量词默认匹配模式是贪婪匹配,尽可能多的匹配。在量词后面加上 ? 可以关闭贪婪匹配模式,尽可能少的匹配

多选分支

一个模式可以实现横向和纵向模糊匹配。而多选分支可以支持多个子模式任选其一

/good|nice/,此正则用来匹配 "good" 或 "nice" 字符。使用管道符 | 分割模式,匹配其中之一

分支结构是惰性的,当前面的匹配上了,后面的就不再尝试了

/good|goodbye/ 当我们用这个正则匹配 "goodbye" 时,只会匹配到 "good"

小结

掌握字符组和量词就能解决大部分常见的情形

位置匹配

位置

位置 (锚) 是相邻字符之间的位置,对于位置的理解,我们可以理解成空字符 ""

比如 "hello" 字符串等价于如下的形式:

"hello" == "" + "h" + "" + "e" + "" + "l" + "" + "l" + "" + "o" + ""  

也等价于:

"hello" == "" + "" + "hello"

因此,把 /^hello$/ 写成 /^^hello$$$/,是没有任何问题的:

var result = /^^hello$$$/.test("hello")  
console.log(result)  
// => true  

甚至可以写成更复杂的:

var result = /(?=he)^^he(?=\w)llo$\b\b$/.test("hello")  
console.log(result)  
// => true  

也就是说字符之间的位置,可以写成多个。

具体含义
^ 匹配行的开头
$ 匹配行的结尾(从结尾开始匹配)
\b 匹配单词的边界(就是\w 和\W 之间的位置,包括 \w 与 ^ 之间的位置,和 \w 与 $ 之间的位置)
\B 匹配非单词的边界
(?=模式) 匹配模式之前的位置
(?!模式) 匹配不是这个模式之前的位置

括号的作用

分组

/a+/ 匹配连续出现的 "a",而要匹配连续出现的 "ab" 时,需要使用 /(ab)+/

其中括号是提供分组功能,使量词 + 作用于 "ab" 这个整体

分支结构

在多选分支结构 (p1|p2) 中,此处括号的作用也是不言而喻的,提供了分支表达式的所有可能

分组引用 (捕获括号)

当模式被放入括号内,匹配的到结果会被捕获,我们可以使用环境提供的 API 来引用它们

可以使用构造函数的静态属性来引用,RegExp.$1至$9,$num,代表最近匹配上的第几个捕获组

反向引用

在正则本身里也可以引用分组。引用之前的分组中匹配到的结果。使用 \1至\9

\10 代表引用第十个分组匹配结果,而不是\1 和 0,如果想匹配\1 和 0,可以使用 (?:\1)0 或者 \1(?:0)

从外向里,开始匹配分组,最外面的括号为 $1,最里面的括号为 $maxNum。例如:

var regex = /^((\d)(\d(\d)))\1\2\3\4$/  
var string = "1231231233"  
console.log(regex.test(string)) // true  
console.log(RegExp.$1) // 123  
console.log(RegExp.$2) // 1  
console.log(RegExp.$3) // 23  
console.log(RegExp.$4) // 3  

如果引用不存在的分组,正则不会报错,只是匹配反向引用的字符本身。

例如 \2,就匹配 "\2"。注意 "\2" 表示对 "2" 进行了转义

分组后面有量词的话,分组最终捕获到的数据是最后一次的匹配

var regex = /(\d)+ \1/  
console.log(regex.test("12345 1"))  
// => false  
console.log(regex.test("12345 5"))  
// => true  

非捕获括号

括号中匹配到的内容都会被捕获,如果只是想要括号最原始的功能,而不需要去引用它。可以使用非捕获括号:

(?: 模式)