![[正则表达式系列] 字符匹配](https://static.yancey.app/68747470733a2f2f79616e6365792d6173736574732e6f73732d636e2d6265696a696e672e616c6979756e63732e636f6d2f786a6e776464766b32617a7a776963776d7567642e6a7067.jpeg)
[正则表达式系列] 字符匹配
正则表达式是用于匹配字符串中字符组合的模式,在计算机科学的各个方面都有它的身影,然而学习它却是一件枯燥而困难的事情。得怀于老姚的 《JavaScript 正则表达式迷你书》,内容凝练且有深度,故这次下决心要攻破之。本系列为《JavaScript 正则表达式迷你书》的读书笔记,旨在今后能够游刃有余的使用正则表达式。
模糊匹配
正则表达式是匹配模式, 要么匹配字符, 要么匹配位置. 模糊匹配有两种形式, 分别是 横向模糊匹配 和 纵向模糊匹配.
横向模糊匹配
使用量词 {m,n}
来匹配某个字符出现的个数. 如下面的例子中, 匹配的字符串必须满足: 第一个字符是 a, 最后一个字符是 c, 中间的 b 可以出现 1~4 次.
const str = "abc abbc abbbc abbbbc abbbbbc";
str.match(/ab{1,4}c/g); // [ 'abc', 'abbc', 'abbbc', 'abbbbc' ]
TIPS 关于 String 的 match 方法可参照 JavaScript API 全解析.
纵向模糊匹配
使用字符组 [xyz]
来匹配某个位置应该出现的字符.
const str = "a1c a2c a3c a4c";
str.match(/a[123]c/g); // [ 'a1c', 'a2c', 'a3c' ]
字符组
字符组用于纵向模糊匹配, 它匹配某个位置可以是哪些字符.
范围表示法
如果字符组匹配的字符表示一个范围, 可使用 范围表示法.
const regexp = /[123456abcdefGHIJKLM]/;
// 上面的正则表达式可简化成如下形式
const simplifyRegexp = /[1-6a-fG-M]/;
通过上面的例子可以看出 -
在正则表达式中有特定的含义, 如果恰好要匹配 -
这个字符, 需要用到 转义, 或把 -
字符放到字符组的开头或结尾.
// 下面是纵向匹配 abcde
const regexp = /[a-e]/;
// 若想匹配 - 这个字符, 需要转义
const regexp = /[a\-e]/;
// 或者放到开头或结尾
const regexp = /[-ae]/;
const regexp = /[ae-]/;
排除字符组
即匹配除字符组以外的字符, 如 /A[^a-c]B/
, 第二个字符是除 a, b, c 以外的任何字符.
const str = "AaB AbB AcB AdB";
str.match(/A[^a-c]B/g); // [ 'AdB' ]
内置字符组
正则表达式内置了一些字符组的简写形式, 可参照如下表格.
字符组 | 含义 |
---|---|
\d | 等价于 /[0-9]/ , 表示匹配一个数字字符. d 是 digit 的缩写. |
\D | 等价于 /[^0-9]/ , 表示匹配一个非数字字符. |
\w | 等价于 /[0-9a-zA-Z_]/ , 表示匹配一个数字, 大小写字母或下划线. w 是 word 的缩写. |
\W | 等价于 /[^0-9a-zA-Z_]/ , 表示匹配一个非单词字符. |
\s | 等价于 /[ \t\v\n\r\f]/ , 表示匹配一个空白符. s 是 space 的缩写. |
\S | 等价于 /[^0-9a-zA-Z_]/ , 表示匹配一个非空白符. |
. | 等价于 /[^\n\r\u2028\u2029]/ , 表示通配符. |
TIPS 匹配任意字符可使用
/[\d\D]/
、/[\w\W]
/、/[\s\S]
/ 和/[^]
/ 的任意一个.
量词
字符组用于横向模糊匹配, 它匹配一个字符出现的次数.
内置量词
量词 | 含义 |
---|---|
{m,n} | 至少出现 m 次, 至多出现 n 次. |
{m,} | 至少出现 m 次. |
{m} | 等价于 {m,m} 表示必须出现 m 次. |
? | 等价于 {0,1} 表示要么出现要么不出现. |
+ | 等价于 {1,+} 表示至少出现一次. |
* | 等价于 {0,} 表示出现任意次. |
贪婪匹配和惰性匹配
贪婪与惰性模式影响的是被量词修饰的子表达式的匹配行为, 贪婪模式在整个表达式匹配成功的前提下, 尽可能多的匹配; 而惰性模式在整个表达式匹配成功的前提下, 尽可能少的匹配.
下面的示例是经典的爬虫正则. 第一个是贪婪匹配, 在匹配到第一个 </div>
时已经可以使整个表达式匹配成功, 但由于采用的是贪婪模式, 所以仍然要向右尝试匹配, 查看是否还有更长的可以成功匹配的子串,在匹配到第二个 </div>
后, 向右再没有可以成功匹配的子串, 此时匹配结束. 对于惰性匹配, 它会从左到右找出字符串中每个可以配对的 <div>
和 </div>
进行匹配, 找到一对就算一对.
const str = "<main><div>test1</div>bb<div>test2</div><main/>";
// 贪婪匹配
str.match(/<div>.*<\/div>/g); // [ '<div>test1</div>bb<div>test2</div>' ]
// 惰性匹配
str.match(/<div>.*?<\/div>/g); // [ '<div>test1</div>', '<div>test2</div>' ]
下面这个例子, 正则匹配 2-5 位的数字. 对于贪婪匹配, 它会尽量匹配多的字符, 也就是子串有 5 位就能匹配到 5 位, 有 3 位就能匹配到 3 位; 而对于惰性匹配, 它会尽量少的匹配字符, 也就是尽量以 2 位去匹配.
const str = "123 1234 12345 123456";
// 贪婪匹配
str.match(/\d{2,5}/g); // [ '123', '1234', '12345', '12345' ]
// 惰性匹配
str.match(/\d{2,5}?/g); // [ '12', '12', '34', '12', '34', '12', '34', '56' ]
因此, 对于上述的量词, 通过后面加一个 ?
可实现其惰性形式.
惰性量词 | 贪婪量词 |
---|---|
{m,n}? | {m,n} |
{m,}? | {m,} |
?? | ? |
+? | + |
*? | * |
多选分支
通过 |
来分割子模式, 表示可匹配其中任意一个子模式. 注意多选分支遵从惰性模式, 下面的例子中, 匹配到 good
后就不再考虑后面的 goodbye
了.
const str = "goodbye, seishun.";
str.match(/good|goodbye/g); // good
训练营
匹配 Hex 色值
下面拆解十六进制颜色:
开头是
#
后面可以是 3 位, 也可以是 6 位
每位字符可以是 0-9, a-f 或 A-F
// 注意多选分支是惰性匹配
// 所以要把匹配长度多的放到前面来
// 因此 [0-9a-fA-F]{6} 要先于 [0-9a-fA-F]{3}
const hexRegExp = /\#[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/g;
"#ffbbad #Fc01DF #FFF #ffE skr 鸡你太美".match(hexRegExp); // [ '#ffbbad', '#Fc01DF', 'FFF', 'ffE' ]
匹配 24 小时时间
const timeRegExp = /^(0?[\d]|1[\d]|2[0-3]):(0?[\d]|[1-5][\d])$/;
timeRegExp.test("23:59"); // true
timeRegExp.test("02:07"); // true
timeRegExp.test("2:7"); // true
timeRegExp.test("42:37"); // false
匹配日期
const dateRegExp = /^([\d]{4})-(0?[1-9]|1[0-2])-(0?[1-9]|[12][\d]|3[01])$/;
dateRegExp.test("2019-03-08"); // true
dateRegExp.test("2019-3-2"); // true
dateRegExp.test("2019-3-92"); // false
匹配系统路径
const pathRegExp = /^[a-zA-Z]:\\([^\\:*<>|"?\r\n/]+\\)*([^\\:*<>|"?\r\n/]+)?$/;
pathRegExp.test("F:\\study\\javascript\\regex\\regular expression.pdf"); // true
pathRegExp.test("F:\\study\\javascript\\regex\\"); // true
pathRegExp.test("F:\\study\\javascript"); // true
pathRegExp.test("F:\\"); // true
匹配 html 元素的 id 属性
const idRegExp = /id=".*?"/;
const idRegExp1 = /id="[^"]*"/; // 这个效率高
idRegExp1.test('<div id="container" class="main"></div>'); // true

PREVIOUS POST
回到顶部的几种玩法

NEXT POST
深入理解并手写遵循 Promise/A+ 规范的 Promise