正则表达式学习记录(一)——正则表达式的编写
文章目录
正则表达式的编写
交互式学习正则表达式:RegexOne 中文
正则表达式练习:RegExr
正则表达式文档:MDN Web Docs 正则表达式
基础篇
标记 |
说明 |
样例 |
---|---|---|
直接匹配,输入什么匹配什么。 | RegEx: abc Match: abc Match: xyz abc def |
|
. |
匹配任何单个字符。 | RegEx: .a Match: 12 3a bc |
\ |
转义字符,用于匹配某个用于标记的原始字符。 | RegEx: \. Match: Hi . Match: 3 . 14 |
[] |
匹配特定范围内的单个字符 | RegEx: [abc]an Match: ban anaMatch: ab can |
[-] |
用简略的方式表示范围。例如 [2-6] 等价于 [23456] |
RegEx: [0-3][a-c] Match: 1a 2b 8y9z |
[^] |
排除特定范围内的单个字符 | RegEx: b[^e]r Match: bar ber |
\d |
匹配 0-9 中的单个数字字符,相当于 [0-9] |
RegEx: \da Match: 0 1a 2b34 |
\D |
匹配单个非数字字符,相当于 [^0-9] |
RegEx: \D2 Match: 1a a2 b34 |
\s |
匹配单个空白字符,相当于 [\f\n\r\t\v\u0020\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff] 。其中, \f \n \r \t \v 与 ASCII 字符集中相同记号的转义字符同义,\uhhhh 为 Unicode 字符集对应字符的编号。 |
RegEx: \s Match: Hello, world! |
\S |
匹配单个非空白字符,相当于 [^\f\n\r\t\v\u0020\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff] 。 |
RegEx: \S Match: H e l l o , w o r l d ! |
\w |
匹配单个单字字符,等价于 [A-Za-z0-9_] 。 |
RegEx: \w Match: 3 .14 |
\W |
匹配单个非单字字符,等价于 [^A-Za-z0-9_] |
RegEx: \W Match: 3 . 14 |
\b |
表示单词边界,匹配一个单词的开始或结束,而不匹配任何实际字符。 | RegEx: \bword\b Match: word and sword |
\B |
表示非单词边界,匹配字母或数字中间的位置,而不匹配任何实际字符。 | RegEx: \d\B\w\B Match: 0 1A BMatch: A 4A 2-g74t |
+ |
用于匹配 1 个或更多前面的标记。 | RegEx: a+b+ Match: aaabb |
* |
用于匹配任意多个前面的标记,匹配的前面标记的数量可以为 0。 | RegEx: a+b*c Match: aaabbbc ccMatch: aaac cc |
? |
用于匹配前一个标记出现 0 次或 1 次。 | RegEx: apples? Match: apple Match: apples s |
{} |
用于匹配指定数量的前一个标记。 | RegEx: \d{2} Match: Jan 14 , 20 05 |
|
用于匹配指定数量范围的前一个标记,, 后可以为空。当 , 后留空时,则标识匹配前一个标记的最小值。 |
RegEx: \d{3,} Match: Jan 14, 2005 |
^ |
放在标记前,用于匹配开头的字符。 | RegEx: ^[Oo]n[Ee] Match: One by onE |
$ |
放在标记后,用于匹配末尾的字符。 | RegEx: [Oo]n[Ee]$ Match: One by onE |
| |
或,| 前后的条件满足一个即可匹配 |
RegEx: I love dogs. Match: I love cats. |
进阶篇
- 捕获组
捕获组用 ()
表示,括号中的内容为一组。在一个正则表达式中的捕获组,按照上括号 (
的顺序进行编号,对于嵌套捕获组同样适用。例如在表达式 ((\d+) plus )\d+
中,捕获组 ((\d+) plus )
的编号为 1,而 \d+
这一捕获组的编号为 2。
在正则表达式中,\
后直接加一个数字 n 相当于“复制”了第 n 个捕获组,从而允许表达式匹配相同的内容。例如,对于表达式 (\w{3}) plus \1
就可以匹配 "one plus one","two plus two",但是无法匹配 "one plus two"。
如果不想让某个捕获组获得编号,可以在 (
后加入 ?:
,这样捕获组就会成为非捕获组,非捕获组不会获得编号。例如对于 "one plus one, two plus two" 这个字符串中除去 ,
之外的内容,可以使用 ((\w{3}) plus \2)
匹配,也可以使用 (?:(\w{3}) plus \1)
匹配。
- 零宽断言
零宽断言有四种,分别是零宽正向先行断言 (?=)
(指定后缀)、零宽正向后行断言 (?<=)
(指定前缀)、零宽负向先行断言 (?!)
(指定后缀不是)、零宽负向后行断言 (?<!)
(指定前缀不是)。其中,被指定为或不为前缀或后缀的内容放在零宽断言中下括号 )
前,先行断言置于标记后,后行断言置于标记前,且零宽断言只用于限定而不参与匹配。
例如我们想匹配 "hopefully seriously" 这两个单词中 "ly" 前的部分,即 "hopeful" 和 "serious",就可以使用零宽正向先行断言匹配后缀为 "ly" 的内容,因此我们使用表达式 \w+(?=ly)
进行匹配,并且 "ly" 并不会被匹配。如果我们想匹配 "Qty.: 100, Price: £150" 中数量 "Qty." 对应的值,则可使用 (?<!£)\d{3}
- 懒惰匹配
正则表达式默认遵循“贪婪匹配”原则,即尽可能匹配多的字符。例如使用表达式 a\w+c
匹配字符串 "abcabc" 时,会匹配整个字符串,而非单独某一段 "abc"。如果想让匹配尽量短,则可以使用 “懒惰匹配” 模式。懒惰匹配有如下几种模式:+?
(出现至少一次,但是长度尽量短)、*?
(出现任意次,但是长度尽量短)、??
(至多出现一次,但是长度尽量短)、{,}?
(出现指定次数,但是长度尽量短)。
例如对于字符串 "abcabc",若需要其匹配为两段 "abc",则可以使用表达式 a\w+?c
。使用表达式 a\w{2,7}?c
可以匹配到 "abbbbcabbcabc" 的 "abbbc" 和 "abbc",而非将 "abbbcabbc" 作为一个整体匹配。
另外需要注意的是,正则表达式从字符串的开头开始匹配,使用懒惰匹配只会改变匹配到的结尾的位置,而非开头的位置。例如使用 a\w*?c
匹配字符串 "aaaccc" 会得到 "aaac" 而非 "ac"。
- 标志位
到目前为止,本文中出现的所有正则表达式都未使用标志位,而前文中所有的表达式都是默认使用 /g
作为标志位得到的相应的结果。正则表达式中有如下常见标志位:g
(global,全局匹配)、i
(case intensitive,不区分大小写)、m
(multiline,多行匹配)、s
(single line,单行匹配)。
对于上面的正则表达式 a\w*?c
,其完整的写法是 /a\w*?c/g
。例如在匹配 "jack_gdn JackGDN JGDN" 这几个单词时,一个完整的正则表达式是 /j.*?gdn/gi
。s
标志位会将多行内容看作一行内容,并且去除 \n
或 \r\n
。m
标志位对于 ^
和 $
标记格外有用。例如对于一段文本:
1jack_gdn
2JackGDN
3JGDN
如果使用 /^j.*?gdn/gi
匹配,则只会匹配到第一行的 "jack_gdn",而如果使用 /^j.*?gdn/gim
匹配,则会将三行内容全部匹配上。