# 正则表达式

# 什么是正则表达式?

正则表达式(Regular Expression)是一种用来描述文本模式的方法。它可以用来匹配、查找、替换文本中的特定模式。在处理文本时,正则表达式是一种非常强大和灵活的工具。

# 为什么学习正则表达式?

  • 有效性:正则表达式可以帮助你更快速、更精确地处理文本。
  • 通用性:几乎所有编程语言和文本编辑器都支持正则表达式。
  • 灵活性:可以根据具体需求编写不同的匹配模式。

# 基本语法

# 1. 元字符与普通字符

  • 元字符

元字符包括 . * + ? [ ] ^ $ | ( ) { } \,它们均有特殊含义。

  • 普通字符

除了元字符外均是普通字符,一串普通字符就是最简单的正则表达式,它们只匹配与自身相等的字符串,例如 abc 匹配字符串 "abc"。

# 2. 匹配任意字符

符号 . 用于匹配一个任意字符(换行符除外,除非在 DotAll 模式下)。

例如 a.c 可匹配字符串 "abc"、"adc", a..c 可匹配字符串 "abdc"、"axzc"。

需要匹配多少个任意字符,就写多少个 .,但如果数量太多或者数量不确定,就难以处理,此时需要用到重复匹配。

# 3. 重复匹配

符号 含义
* 匹配前一个字符或分组 0 次或多次,例如 ab*c 可匹配字符串 "ac"、"abc"、"abbc"。
+ 匹配前一个字符或分组 1 次或多次,例如 ab+c 可匹配字符串 "abc"、"abbc"、"abbbc"。
? 匹配前一个字符或分组 0 次或 1 次,例如 ab?c 匹配字符串 "ac" 或 "abc"。
{n} 匹配前一个字符或分组恰好 n 次,例如 ab{5}c 匹配字符串 "abbbbbc"。
{n,} 匹配前一个字符或分组至少 n 次,例如 ab{2,}c 可匹配字符串 "abbc"、"abbbc"。
{n,m} 匹配前一个字符或分组至少 n 次,最多 m 次,例如 ab{0,2}c 可匹配字符串 "ac"、"abc"、"abbc"。

有了重复匹配,就可以实现匹配例如以 "a" 开头以 "b" 结尾的任意文本:a.*b

# 贪婪匹配

正则表达式的贪婪匹配是指正则表达式引擎在匹配时尽可能多地匹配字符的特性。具体来说,正则表达式的贪婪匹配会尽量匹配最长的字符串,直到不能再匹配为止。

在正则表达式中,重复次数符号(如 *+?{})默认是贪婪匹配的,也就是会尽可能地匹配更多的字符。例如,对于表达式 a.*b,如果在文本中有多个匹配结果,则贪婪匹配会匹配最长的字符串,直到最后一个 "b"。

如果想要关闭贪婪匹配,可以在重复次数后面加上 ?,表示非贪婪匹配。例如,*?+???{n,}?{n,m}?。这样会使得匹配尽可能少的字符,即匹配到满足条件的第一个字符就停止。

假设有文本:"<h>ABC</h>",正则表达式 <.+> 会贪婪匹配整个字符串 "<h>ABC</h>",若只需匹配 "<h>" 则需要使用非贪婪正则表达式 <.+?>

贪婪匹配在实际使用中需要根据具体需求来决定是否使用非贪婪匹配,以确保匹配结果符合预期。

# 4. 字符集合

中括号 [ ] 用于匹配括号内的任意一个字符,例如 [abc] 可匹配 "a"、"b" 或 "c" 中的任意一个。

也可以使用 - 连接两个字符来表示范围,例如 [a-z] 可匹配从 "a" 到 "z" 中的任意一个字母。

以上两种写法可以组合,例如 [_a-zA-Z] 可匹配一个下划线或英文字母。

在括号内容开头加上 ^ 则表示取反,例如 [^0-9] 可匹配任意一个非数字字符。

# 5. 边界匹配

  • ^:匹配输入字符串的开始。

例如:^abc 匹配以 "abc" 开头的字符串。

  • $:匹配输入字符串的结尾。

例如:xyz$ 匹配以 "xyz" 结尾的字符串。

  • \b:匹配单词边界。

例如:\bword\b 匹配单词 "word",但不匹配 "sword" 或 "words" 中的 "word"。

多行模式下,^$ 分别匹配一行的开头和结尾,MT 文本编辑器的正则搜索默认开启多行模式。

# 6. 分组匹配

将一段正则表达式使用 ( ) 包围起来即可让它们成为一个整体,例如 word+ 中只是对 "d" 进行多次匹配,比如 "wordddddd";而 (word)+ 会对 "word" 进行多次匹配,比如:"wordwordword"。

同时被 ( ) 包围起来的部分也会成为捕获组

# 7. 选择匹配

符号 | 表示匹配其左边或右边的内容,其选择范围为所在分组或者整个正则表达式

例如:cat|dog 可匹配 "cat" 或 "dog",g(oo|uar)d 可匹配 "good" 或 "guard"。

# 8. 捕获组

( ) 包围起来的分组也称为捕获组,它会被正则引擎记录下来,捕获组的序号是根据 ( 从左往右的顺序从 1 开始算。

例如 a(b(c)) 中有 2 个捕获组,1 号捕获组会匹配 "bc",2 号捕获组会匹配 "c"。

捕获组可用于向后引用或者替换:

  • 用于向后引用

例如正则表达式 (.)\1 可匹配两个连续的相同字符,其中 . 用于匹配任意字符,并且它处于 1 号匹配组,\1 表示引用 1 号匹配组的内容。

(.)\1 表示先匹配一个任意字符,然后再重复匹配一次这个字符,最后可得到两个连续的相同字符。

  • 用于替换

对于文本 "<a><b><c>" 如果要将它替换为 "<aa><bb><cc>",那么可以使用正则表达式 <(.+?)> 和替换表达式 <$1$1> 来实现。

在替换表达式中,$n 用于表示第 n 个捕获组的内容,如果 n 大于等于 10 则需写成 ${n},如 ${10}

关于替换表达式的更多说明可查看后续内容

# 9. 非捕获组

有时需要将一部分正则表达式包围起来成为一个整体,但又不希望它被捕获,那么就需要用到非捕获组 (?: ),例如 (?:a+)(b+) 中仅有一个捕获组。

还有一类更加特殊的分组,它们不但不会被捕获,还不会匹配具体文本,仅起到预查的作用:

符号 含义
(?= ) 正向肯定预查,例如,Windows(?=XP) 能匹配 "WindowsXP" 中的 "Windows",但不能匹配 "Windows11" 中的 "Windows"。
(?! ) 正向否定预查,例如,Windows(?!XP) 能匹配 "Windows11" 中的 "Windows",但不能匹配 "WindowsXP" 中的 "Windows"。
(?<= ) 反向肯定预查,例如,(?<=XP)Windows 能匹配 "XPWindows" 中的 "Windows",但不能匹配 "11Windows" 中的 "Windows"。
(?<! ) 反向否定预查,例如,(?<!XP)Windows 能匹配 "11Windows" 中的 "Windows",但不能匹配 "XPWindows" 中的 "Windows"。

# 10. 转义符号

在元字符前面加上 \ 即可变为普通字符,例如 \. 匹配句点 ".",\\ 匹配反斜杠 "\"。

[ ] 中使用 \ 也可以使 -^ 变为普通字符,例如 [\^\-] 匹配 "^" 或 "-"。

除此之外 \ 还有许多其它用法:

符号 含义
\b 匹配一个单词的边界,也就是指单词和空格间的位置,例如 \bword\b 匹配单词 "word",但不匹配 "sword" 或 "words"。
\B 匹配非单词边界,例如 er\B 能匹配 "verb" 中的 "er",但不能匹配 "never" 中的 "er"。
\d 匹配一个数字字符,等价于[0-9]
\D 匹配一个非数字字符,等价于 [^0-9]
\s 匹配任何不可见字符,包括空格、制表符、换页符等等,等价于 [ \f\n\r\t\v]
\S 匹配任何可见字符,等价于 [^ \f\n\r\t\v]
\w 匹配包括下划线的任何单词字符,等价于 [A-Za-z0-9_]
\W 匹配任何非单词字符,等价于[^A-Za-z0-9_]
\uXXXX Unicode 转义字符序列,例如 \u00A9 匹配著作权符号(©)。
\xNN 十六进制转义字符序列,例如,\x41 匹配 "A"
\num 引用第 num 个捕获组的匹配,例如 (.)\1 匹配两个连续的相同字符。
\n 匹配一个换行符。
\r 匹配一个回车符。
\f 匹配一个换页符。
\t 匹配一个制表符。
\v 匹配一个垂直制表符。

这些符号也可以在字符集合中使用,例如 [a-z0-9][a-z\d] 是等价的。

# 11. 修饰符

修饰符 说明
(?i) 不区分大小写。例如,"(?i)hello" 将匹配 "hello","Hello","HELLO" 等。
(?m) 多行模式。在这种模式下,^$ 将匹配每一行的开始和结束,而不仅仅是整个输入的开头和结尾。
(?s) 开启 DotAll 模式。在这种模式下,. 将匹配任何字符,包括换行符。
(?u) 启用后不区分大小写的匹配将以符合 Unicode 标准的方式完成。

MT 文本编辑器的搜索功能默认开启 (?m) 多行模式

在修饰符的字母前面加上 - 即可去掉修饰符效果:(?-i)(?-m)(?-s)(?-u)

例如正则表达式 (?i)a(?-i)a 可以匹配 "aa" 和 "Aa",其中第一个 a 不区分大小写,第二个 a 区分大小写。

# 正则替换

正则替换的优势在于你可以在替换内容中插入任意捕获组内容。

在替换表达式中,$n 用于表示第 n 个捕获组的内容,如果 n 大于等于 10 则需写成 ${n},如 ${10}

捕获组的序号从 1 开始,但你也可以使用 $0,因为它表示整个匹配到的文本。

例如对于以下文本可用 (\d+)-(\d+) 来匹配:

000-111
222-333
444-555

如果要调换左右两个数字的位置,可替换为 $2-$1

如果要在前后加上双引号,可替换为 "$0"

# 转义符号

符号 含义
\n 表示换行符
\r 表示回车符
\t 表示制表符
\$ 表示符号 $
\\ 表示符号 \

因为替换表达式中 $ 表示捕获组序号,如果你只是单纯的想把查找到的内容替换为 $ 这个字符,那么替换表达式就是 \$

# 大小写处理

该功能不属于正则表达式的规范,仅从 MT 2.17.2 版本开始支持,其它软件可能不支持或者使用了其它语法!

符号 说明
\l 把一个字符转为小写
\u 把一个字符转为大写
\L 把剩余字符转为小写
\U 把剩余字符转为大写

具体使用时还需要加上捕获组序号,例如:

  • \L$0:将整个匹配文本转为小写。
  • \u$2:将第 2 个捕获组内容的第一个字符转为大写,剩余字符保持不变。
  • \u\L$0:将整个匹配文本的第一个字符转为大写,剩余字符转为小写。
  • \l\l${10}:将第 10 个捕获组内容的第一、二个字符转为小写,剩余字符保持不变。