正规表示式 (Regular Expression) 语法整理
正规表示式 (Regular Expression, 简写 regex、regexp 或 RE) 是用于字串比对的小型语言,又称正则表达式、正规表示法、规则运算式、常规表示法 (Wiki)。
很多程式语言和软件都会附加“正规表示式”这项功能。在字串的处理上,针对大量、重复、有固定逻辑的文字,正规表示式是非常强而有力的工具! 即便不是程式设计师,在可以在运用到正规表示式的场合 (例如: 文字编辑器),能帮你节省许多文字处理的时间。但是不同的软件所附加的正规表示式可能略有差异,这部份就要稍加留意。
不过在初学者的眼中,正规表示式却又像是天书一样的难以理解。以下文章针对正规表示式的相关语法做解说,你可到线上测试工具,以实际的例子去做测试。
语法整理 (Pattern)
字符符号
- .: 任意文字、数字及符号,但不包括换行
- \d: 任意数字 (同 [0-9])
- \w: 任意文字、数字或底线 (同 [0-9a-zA-Z_])
- \s: 任意空白字符,包含空白、定位、换行字符 (同 [ \t\n])
- \D: 任意非数字
- \W: 任意非文字、数字或底线
- \S: 任意非空白字符 (同 [^ \t\n])
- \n: 换行字符
- \t: 定位字符
-
\OCT: 八进制字符,ex: \101 = "A"
-
\xHEX: 十六进制字符,ex: \x41 = "A"
- \uUnicode: Unicode 字符,ex: \u4F60 = "你"。
另外,Unicode 中文范围: [\u4E00-\u9FA5],中日韩文字范围: [\u4E00-\u9FFF] - \: 不转译控制符号
一般状态下,字符符号都不包括换行字符 (\n),因此遇到“换行”就会停止比对。在某些环境下可以启用多行模式 (Multiline),则换行字符 (\n) 会被视为一般文字。
字符列举
列举的原则:
- 放在中括号 [ ... ] 里的字符皆为单独比对的字符
- 在中括号内加 ^ 表示“反向列举”
- 可以用 - 来代表连续的字符范围
范例:
- [0123456789]: 任意数字 (同 \d)
- [0-9]: 任意数字,同 (同 \d)
- [a-z]: 任意小写英文字母
- [a-zA-Z]: 任意大小写的英文字母
- [0-9a-zA-Z]: 任意数字、英文字母
- [^x]: 反向列举,任意非 x 的字符
- [^0-9]: 反向列举,任意非数字 (同 \D)
字串行举
- |: 或
次数符号、限定符号
- *: 重复 0 次以上 (同 {0,}) *贪婪原则
- +: 重复 1 次以上 (同 {1,}) *贪婪原则
- ?: 重复 0 或 1 次 (同 {0,1}) *贪婪原则
- {n}: 重复 n 次
- {n,}: 重复 n 次以上 *贪婪原则
- {0,n}: 重复 0 ~ n 次 *贪婪原则
- {n,m}: 重复 n ~ m 次 *贪婪原则
说明:
- 所有的“次数符号”都会极大化 (Infinite) 要比对的范围,称为“贪婪原则”。
ex: .*\d+ 因为贪婪原则,前面的 .* 就已经涵盖后面的 \d+ 所要比对的数字了,因此 \d+ 在这里是多余的! - 如果要取消“贪婪原则”,只要在次数符号的后面加上 ? 即可让它节制一点、不要那么的贪婪,让放在后面的比对规则也可以有作用。因此,上面的范例就变成: .*?\d+。
- 在实务上,我们不太会将 * 与 ? 这两个次数符号放在正规表示式的最后,因为它们两者都允许“重复 0 次”,因为比对之后可能会多出“空白”的结果。
边界符号
- ^: 要在行的开头 (Start of line)
- $: 要在行的结尾 (End of line)
- \b: 必须是单词 (文字、数字、底线) 的开头或结尾
- \B: 不能是单词 (文字、数字、底线) 的开头或结尾
进阶
群组
- 可以使用小括号 ( ... ) 将既有的规则组合成一个“群组”
- 建立规则群组之后,可再以此群组为基础,套用其它的规则
- 可以用 \1 ... \9 来代表前面符合的群组
- 当要储存或取代比对的内容时,可以用 $1 .. $9 (或 \1 ... \9) 来代表各群组
判断式
右合、正看 (Lookahead):
-
Pattern1(?:Pattern2): 符合 Pattern1 并且右方符合 Pattern2 才算符合全部的 Patternex: Windows(?:95|98|2000) 可符合 Windows95,但不符合 WindowsNT
-
Pattern1(?=Pattern2): 符合 Pattern1 并且右方符合 Pattern2 才算符合 Pattern1
白话文: 我要找 Pattern1,其右方必须为 Pattern2ex: Windows(?=95|98|2000) 可符合 Windows95 的 Windows,但不符合 WindowsNT 的 Windows -
Pattern1(?!Pattern2): 符合 Pattern1 但右方不符合 Pattern2 才算符合 Pattern1
白话文: 我要找 Pattern1,但右方不能为 Pattern2ex: Windows(?!95|98|2000) 可符合 Widnows 或 WindowsNT 的 Windows,但不符合 Windows95 的 Windows
左合、回头看 (Lookbehind):
- (?<=Pattern1)Pattern2: 符合 Pattern2 并且左方符合 Pattern1 才算符合 Pattern2
白话文: 我要找 Pattern2,其左方必须为 Pattern1
ex: (?<=Chapter|Section)[\d]+ 可符合 Chapter15 的 15,但不符合 Topic15 的 15 - (?<!Pattern1)Pattern2: 符合 Pattern2 但左方不符合 Pattern1 才算符合 Pattern2
白话文: 我要找 Pattern2,但左方不能为 Pattern1
ex: (?<!Chapter|Section)(?<!\d)[\d]+ 可符合 Topic15 的 15,但不符合 Chapter15 的 15
说明:
- 以上判断式的小括号 (? ... ) 并不会成为“群组”
- 并非所有的环境都能完整支援判断式的用法
线上测试
- Regular Expressions 101
- RegEx Testing
- 正规表示式线上测试-站长工具
- Regulex: JavaScript Regular Expression Visualizer - 将正规表示式图形化
- Regexper - 将正规表示式图形化
- 编程胶囊 - 教学与题目练习
- RegexOne - 题目练习
No comments yet.