C# 正则表达式

正则表达式 是一种用来描述、匹配文本模式的搜索公式。简单来说,你可以把它理解成一套特殊的通配符语言,用来精确地找到、验证或替换字符串中的内容。

例如,想判断用户输入的是不是一个合法的邮箱地址、手机号,或者想从一段文本里提取所有日期——这些都是正则表达式的典型应用场景。

.NET 框架内置了功能完善的正则表达式引擎,通过 System.Text.RegularExpressions 命名空间提供支持。

一个正则表达式模式由一个或多个字符、运算符和结构组成,它们共同描述要匹配的文本规则。

如果你还不理解正则表达式可以先阅读我们的正则表达式 - 教程

定义正则表达式

正则表达式由以下几类构建块组成,每类负责不同的匹配功能:

  • 字符转义:让特殊字符被当作普通字符处理(如 \. 匹配真正的句点)
  • 字符类:匹配"某一类"字符(如 \d 匹配任意数字)
  • 定位点:指定匹配发生的"位置"(如 ^ 表示行首)
  • 分组构造:将子模式组合在一起,方便捕获或引用
  • 限定符:控制某个元素出现的次数(如 + 表示一次或多次)
  • 反向引用构造:引用前面已捕获的内容进行再次匹配
  • 备用构造:实现"或"逻辑(如 cat|dog
  • 替换:在替换操作中引用捕获的内容
  • 杂项构造:内联选项、注释等辅助功能

字符转义

正则表达式中,反斜杠字符(\)有两个作用:一是将其后的普通字符变成特殊含义(如 \n 表示换行),二是将特殊字符转义为原义字符(如 \. 匹配真实的点号而非"任意字符")。

初学者常见误区:在 C# 字符串中,\ 本身也是转义字符,所以正则中写 \d,在 C# 字符串里要写 "\\d",或者使用逐字字符串 @"\d"(推荐)。

下表列出了常用的转义字符:

转义字符 描述 模式 匹配
\a 与报警 (bell) 符 \u0007 匹配。 \a "Warning!" + '\u0007' 中的 "\u0007"
\b 在字符类中,与退格键 \u0008 匹配。(注意:在字符类外,\b 表示单词边界,见"定位点"部分) [\b]{3,} "\b\b\b\b" 中的 "\b\b\b\b"
\t 与制表符 \u0009 匹配。常用于匹配 Tab 分隔的文本 (\w+)\t "Name\tAddr\t" 中的 "Name\t" 和 "Addr\t"
\r 与回车符 \u000D 匹配。(\r 与换行符 \n 不是等效的。Windows 换行通常是 \r\n) \r\n(\w+) "\r\nHello\nWorld." 中的 "\r\nHello"
\v 与垂直制表符 \u000B 匹配。 [\v]{2,} "\v\v\v" 中的 "\v\v\v"
\f 与换页符 \u000C 匹配。 [\f]{2,} "\f\f\f" 中的 "\f\f\f"
\n 与换行符 \u000A 匹配。Unix/Linux 系统的行尾通常只有 \n。 \r\n(\w+) "\r\nHello\nWorld." 中的 "\r\nHello"
\e 与转义符 \u001B 匹配。 \e "\x001B" 中的 "\x001B"
\ nnn 使用八进制表示形式指定一个字符(nnn 由二到三位数字组成)。 \w\040\w "a bc d" 中的 "a b" 和 "c d"
\x nn 使用十六进制表示形式指定字符(nn 恰好由两位数字组成)。 \w\x20\w "a bc d" 中的 "a b" 和 "c d"
\c X
\c x
匹配 X 或 x 指定的 ASCII 控件字符,其中 X 或 x 是控件字符的字母。 \cC "\x0003" 中的 "\x0003" (Ctrl-C)
\u nnnn 使用十六进制表示形式匹配一个 Unicode 字符(由 nnnn 表示的四位数)。 \w\u0020\w "a bc d" 中的 "a b" 和 "c d"
\ 在后面带有不识别的转义字符时,与该字符匹配。 \d+[\+-x\*]\d+\d+[\+-x\*\d+ "(2+2) 39" 中的 "2+2" 和 "3*9"

字符类

字符类用于匹配"某一类"字符中的任意一个。例如 [aeiou] 匹配任意一个元音字母,\d 匹配任意一个数字。这是正则表达式中最常用的基础功能之一。

下表列出了字符类:

字符类 描述 模式 匹配
[character_group] 匹配 character_group 中的任何单个字符。 默认情况下,匹配区分大小写。 [mn] "mat" 中的 "m","moon" 中的 "m" 和 "n"
[^character_group] 非:与不在 character_group 中的任何单个字符匹配。 默认情况下,character_group 中的字符区分大小写。 [^aei] "avail" 中的 "v" 和 "l"
[ first - last ] 字符范围:与从 first 到 last 的范围中的任何单个字符匹配。 [b-d] [b-d]irds 可以匹配 Birds、 Cirds、 Dirds
. 通配符:与除 \n 之外的任何单个字符匹配。
若要匹配原意句点字符(. 或 \u002E),您必须在该字符前面加上转义符 (.)。
a.e "have" 中的 "ave", "mate" 中的 "ate"
\p{ name } name 指定的 Unicode 通用类别或命名块中的任何单个字符匹配。 \p{Lu} "City Lights" 中的 "C" 和 "L"
\P{ name } 与不在 name 指定的 Unicode 通用类别或命名块中的任何单个字符匹配。 \P{Lu} "City" 中的 "i"、 "t" 和 "y"
\w 与任何单词字符匹配(字母、数字、下划线)。等价于 [a-zA-Z0-9_](ASCII 范围内)。 \w "Room#1" 中的 "R"、 "o"、 "m" 和 "1"
\W 与任何非单词字符匹配。是 \w 的反义。 \W "Room#1" 中的 "#"
\s 与任何空白字符匹配(空格、制表符、换行等)。 \w\s "ID A1.3" 中的 "D "
\S 与任何非空白字符匹配。是 \s 的反义。 \s\S "int _ctr" 中的 " "
\d 与任何十进制数字匹配。等价于 [0-9]。 \d "4 = IV" 中的 "4"
\D 匹配不是十进制数的任意字符。是 \d 的反义。 \D "4 = IV" 中的 " "、 "="、 " "、 "I" 和 "V"

定位点

定位点(也叫"锚点")不匹配任何具体字符,而是匹配字符串中的某个位置。它们是"零宽度"的,不消耗任何字符,只是断言当前位置满足某个条件。

例如 ^\d{3} 表示"字符串开头的三个数字",\b 表示"单词与非单词字符之间的边界"。

下表列出了定位点:

断言 描述 模式 匹配
^ 匹配必须从字符串或一行的开头开始。 ^\d{3} "567-777-"