正则表达式简明教程

75 阅读3分钟

普通字符

普通字符,也称为字面量 (Literals),是指在正则表达式中直接表示其字面含义的字符。它们没有其他特殊的含义,所见即所得。例如,正则表达式 51job 将匹配字符串中连续出现的 51job 这 5 个字符。

控制字符

一些不可见的控制字符用于匹配特定的格式和布局,这些字符虽然在文本中不可见,但它们在处理文本时起着重要的作用。

  • \r 回车符 (carriage return): 将光标移动到当前行的行首,而不会换到下一行。如果在回车符后继续输出内容,会覆盖当前行之前的内容。
  • \n 换行符 (newline): 将光标移动到下一行的开头,而不会回到行首。通常用于表示行与行之间的分隔。
  • \t 制表符 (tab): 插入一个水平制表符,通常用于对齐文本。制表符的宽度取决于环境的设置,通常是 8 个字符。
  • \f 换页符 (form feed): 将光标移动到下一页的开头。在打印机中,换页符用于指示打印机开始新的一页。
  • \v 垂直制表符 (vertical tab): 将光标移动到下一行的垂直制表位置。虽然在现代文本处理中不常用,但在某些特定环境中仍然有其用途。

字符集合

字符集合使用方括号 [] 来定义,用于匹配集合中的任意一个字符。每次匹配的都是单个字符。例如,[abc] 表示匹配小写字母 abc 中的任意一个字符。我们还可以使用短横线 - 来表示一个范围,从而简化字符集合的定义。例如,[0-9] 表示匹配任意一个从 09 的阿拉伯数字。此外,我们还可以用 [^A-Z] 表示匹配除了大写字母 AZ 以外的任何字符。

为了方便使用,正则表达式预定义了一些常用的字符集合,罗列如下:

  • \d 匹配一个数字字符,等价于 [0-9],其反义为 \D,匹配非数字字符。
  • \w 匹配一个单词字符 (字母、数字或下划线),等价于 [A-Za-z0-9_],其反义为 \W,匹配非单词字符。
  • \s 匹配任何空白字符,包括空格、制表符、换页符等,等价于 [\t\n\v\f\r\x20],其反义为 \S,匹配任何非空白字符。
  • . 匹配除换行符 \n 之外的任何单个字符。

Unicode 字符集合

Unicode 字符集合提供了一种强大的方式来匹配各种字符类型。以下是一些常用的 Unicode 字符集合及其对应的字符范围:

  • \p{Lower}: 匹配小写字母,相当于 [a-z]
  • \p{Upper}: 匹配大写字母,相当于 [A-Z]
  • \p{ASCII}: 匹配 ASCII 字符,相当于 [\x00-\x7F]
  • \p{Alpha}: 匹配字母字符,相当于 [\p{Lower}\p{Upper}]
  • \p{Digit}: 匹配数字字符,相当于 [0-9]\d
  • \p{Alnum}: 匹配字母和数字字符,相当于 [\p{Alpha}\p{Digit}]
  • \w: 匹配字母、数字和下划线字符,相当于 [\p{Alnum}_]
  • \p{Punct}: 匹配标点符号,相当于 [!"#$%&'()*+,-./:;<=>?@[]^_`{|}~]
  • \p{Graph}: 匹配可见字符,相当于 [\p{Alnum}\p{Punct}]
  • \p{Print}: 匹配可打印字符,相当于 [\p{Graph}\x20]
  • \p{Blank}: 匹配空白字符,相当于 [\t\x20]
  • \p{Space}: 匹配空白字符,相当于 [\t\n\v\f\r\x20]\s
  • \p{Cntrl}: 匹配控制字符,相当于 [\x00-\x1F\x7F]
  • \p{XDigit}: 匹配十六进制数字字符,相当于 [0-9a-fA-F]

此外,还有一些特定于 Java 的 Unicode 字符集合:

  • \p{javaLowerCase}: 匹配各种语言的小写字母,范围比 \p{Lower} 更广
  • \p{javaUpperCase}: 匹配各种语言的大写字母,范围比 \p{Upper} 更广
  • \p{javaWhitespace}: 匹配各种空白字符,范围比 \p{Space} 更广,包括中文空白字符

其他常见的 Unicode 字符集合包括:

  • \p{P}: 匹配各种语言的标点符号,范围比 \p{Punct} 更广
  • \p{Ps}: 匹配开始括号
  • \p{Pe}: 匹配结束括号
  • \p{Pi}: 匹配开始引号
  • \p{Pf}: 匹配结束引号
  • \p{Pc}: 匹配连接字符
  • \p{Pd}: 匹配虚线字符
  • \p{Po}: 匹配其他字符
  • \p{S}: 匹配符号
  • \p{Z}: 匹配分隔符
  • \p{IsHan}: 匹配汉字

量词

量词 (Quantifiers):用于指定前面元素的出现次数。通用的写法是 {n,m},表示至少出现 n 次,但不超过 m 次。以下是几种常用的量词表示方法:

  • *:匹配 0 次或多次,相当于 {0,}
  • +:匹配 1 次或多次,相当于 {1,}
  • ?:匹配 0 次或 1 次,相当于 {0,1}
  • {n}:匹配恰好 n 次
  • {n,}:匹配至少 n 次
  • {,m}:匹配至多 m 次

默认情况下,量词匹配是贪婪模式,即尽可能多地匹配字符。例如,正则表达式 a.*b 在字符串 aabbb 中会匹配整个字符串 aabbb。如果希望匹配尽可能少的字符,可以在量词后面加一个问号 ?,表示非贪婪模式。例如,正则表达式 a.*?b 在字符串 aabbb 中会匹配 aab

分组与捕获

圆括号 () 用于将多个字符组合成一个整体进行匹配,并支持后续的量词操作。例如,(abc) 将匹配字符串 "abc",这与 [abc] 匹配单个字符不同。如果你希望匹配 "abc" 或 "def",可以使用 (abc|def),其中竖线 | 表示逻辑或。

括号不仅用于分组,还可以捕获匹配的内容,便于后续引用。例如,匹配的内容可以通过 \1 引用。如果你只需要分组而不需要捕获,可以使用非捕获分组 (?:...)。这种方式可以避免不必要的捕获,提高正则表达式的效率。

位置匹配

位置匹配,也称为锚点 (Anchors),用于匹配字符串中的特定位置。它们都是零宽度的,即它们不匹配任何实际字符,只匹配位置。

  • ^ 匹配字符串的开始。例如,^abc 匹配以 "abc" 开头的字符串。
  • $ 匹配字符串的结束。例如,abc$ 匹配以 "abc" 结尾的字符串。
  • \b 匹配一个单词的边界。例如,\bword\b 匹配完整的单词 "word"。

此外,还有一些更高级的零宽度断言:

  • (?=...) 向前肯定预查,匹配括号内表达式在前的位置。例如,a(?=b) 匹配 "a" 仅当其后跟着 "b"。
  • (?!...) 向前否定预查,匹配括号内表达式在前的位置,但不包括该表达式。例如,a(?!b) 匹配 "a" 仅当其后不跟着 "b"。
  • (?<=...) 向后肯定预查,匹配括号内表达式在后的位置。例如,(?<=a)b 匹配 "b" 仅当其前面是 "a"。
  • (?<!...) 向后否定预查,匹配括号内表达式在后的位置,但不包括该表达式。例如,(?<!a)b 匹配 "b" 仅当其前面不是 "a"。

转义字符

在正则表达式中,许多字符具有特殊含义,例如量词 *+?,锚点 ^$,括号 ()[]{},以及反斜杠 \。如果需要将这些字符视为字面量进行匹配,而不是其特殊含义,可以在它们前面加上反斜杠 \。例如,\+ 匹配字符 "+",也可以放在字符集合中进行匹配,例如 [+] 匹配字符 "+"。

修饰符

  • i 忽略大小写:启用此修饰符后,正则表达式将忽略大小写。
  • g 全局搜索:启用此修饰符后,正则表达式将搜索整个字符串中的所有匹配项,而不仅仅是第一个。
  • m 多行模式:启用此修饰符后,正则表达式中的 ^$ 将匹配每一行的行首和行尾,而不仅仅是整个字符串的开头和结尾。
  • s . 匹配任意字符,包括换行符。
  • u 使用 unicode 码的模式进行匹配。