概念
正则表达式是用来描述查找符合某些复杂规则的字符串的工具, 代表了记录文本规则的代码.
不同环境下正则表达式的一些细节是不同的.
入门表达
- 精确查找单词:
1 | \bword\b |
\b被称为元字符(metacharacter), 代表了单词的开头或结尾, 即单词的分界处, 只匹配一个位置.
- 查找
word0
后面含有word1
的字符:
1 | \bword0\b.*\bword1\b |
*.为元字符, 匹配除了换行符以外的任意字符; ____同样是元字符, 代表数量, 指定该字符前面的内容可以连续重复使用任意次从而使得整个表达式得到匹配; 组合在一起的意思就是任意数量的不包含换行的字符.
- 匹配数字:
1 | \d |
\d匹配一位数字, **-**则不是元字符, 只匹配它本身.
1 | \d{2} |
**\d{2}**避免了命令重复, 代表了对\d重复两次匹配.
- 匹配任意的空白符, 包括空格, 制表符, 换行符, 中文全角空格等.
1 | \s |
- 匹配字母或数字或下划线或汉字等(一位).
1 | \w |
示例
- 匹配以字母a开头的单词, 之后是任意数量的字母或数字__\w*__, 最后是单词结束.
1 | \ba\w*\b |
- 匹配一个或更多个连续的数字:
1 | \d+ |
__*__匹配重复任意次(可能是0次), __+__则匹配重复1次或更多次.
- 匹配刚好6个字符的单词:
1 | \w{6} |
- 匹配字符串的位置:
1 | ^ # 匹配字符串的开始 |
可以用来验证输入的内容.
- 匹配5位到12位数字:
1 | \d{5,12} |
字符转义
- 查找元字符本身:
1 | \* |
重复
- 限定符(指定数量的代码)都会对前面的字符起作用.
限定符 | 说明 |
---|---|
* | 重复零次或更多次(匹配整个字符串) |
+ | 重复一次或更多次(匹配整个字符串) |
? | 重复零次或一次(匹配单个字符) |
{n} | 重复n次(每次都是一个整体匹配) |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
字符类
- 匹配标点符号:
1 | [.?!] # |
- 匹配字符范围:
1 | [0-9] # 数字0-9, 相当于\d |
- 匹配字母和数字:
1 | [a-z0-9A-Z_] # 相当于\w |
上述字符都只会表示一位.
示例
- 首先是一个转义字符__\(, 能够出现0次或1次(?), 然后是一个数字0, 后面跟着2个数字(\d{2}), 之后是**)**或者-或者空格中的一个, 会出现一次或不出现(?__), 最后是8个数字(\d{8}).
1 | \(?0\d{2}[)- ]?\d{8} |
**()**同样是元字符.
分枝条件
- 该条件是指有几种规则, 如果满足其中一种规则都应该当成匹配, 使用**|**把不同的规则分隔开.
示例
1 | 0\d{2}-\d{8}|0\d{3}-\d{7} # 该表达式能匹配两种以连字符分隔的数字串 |
分枝条件匹配时, 将会从左到右的测试每个条件, 如果满足某个分枝得得话, 就不会再管其他的条件了.
分组
- 使用小括号来指定子表达式(分组), 进而指定其重复次数:
1 | (\d{1,3}\.){3}\d{1,3} # ip匹配表达式 |
正则表达式中不提供关于数学的任何功能.
1 | ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?) # 剔除不存在的ip格式 |
反义
- 查找不属于能简单定义的字符类的字符, 语法中的字符为大写:
语法 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符 |
\S | 匹配任意不是空白符的字符 |
\S+ | 匹配不包含空白符的字符串 |
\D | 匹配任意非数字的字符 |
\B | 匹配不是单词开头或结束的位置 |
[^x] | 匹配除了x以外的任意字符 |
[^aeiou] | 匹配除了aeiou这几个字以外的任意字符 |
<a[^>]+> | 匹配用尖括号括起来的以a开头的字符串 |
后向引用
- 默认情况下, 每个分组会自动拥有一个组号, 规则为从左向右, 以分组的左括号为标志, 第一个出现的组号为1, 一次类推. 故后向引用用于重复搜索前面某个分组匹配的文本. 分组0对应整个正则表达式.
1 | \1 # 代表分组1匹配的文本. |
- 指定子表达式的组名:
1 | (?<Word>\w+) # 把尖括号换成单引号也可以 |
上述含义为: 把**\w+**的组名指定为Word, 要反向引用这个分组捕获的内容, 你可以使用\k<Word>
.
示例
1 | \b(\w+)\b\s+\1\b # 匹配重复的单词 |
零宽断言
用于查找在某些内容(不包括这些内容)之前或之后的东西, 即指定一个位置, 这个位置应该满足一定的条件(即断言):
- 零宽度正预测先行断言:
1 | (?=exp) # 断言自身出现的位置的后面能匹配表达式exp |
- 零宽度正回顾后发断言:
1 | (?<=exp) # 断言自身出现的位置的前面能匹配表达式exp |
示例
1 | \b\w+(?=ing\b) # 匹配以ing结尾的单词的前面部分(除了ing以外的部分) |
负向零宽断言
只匹配一个位置, 而不消费任何字符.
- 零宽度负预测先行断言:
1 | (?!exp) # 断言此位置的后面不能匹配表达式exp |
- 零宽度负回顾后发断言:
1 | (?<!exp) # 断言此位置的前面不能匹配表达式exp |
示例
1 | \b\w*q[^u]\w*\b # 匹配包含后面不是字母u的字母q的单词 |
注释
- 通过语法
(?#comment)
来包含注释. (包含注释时, 启用"忽略模式里的空白符"选项), 可以在编写表达式时能任意的添加空格, Tab, 换行, 而实际使用时这些都将被忽略. 启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉.
贪婪与懒惰
- 当正则表达式中包含能接受重复的限定符时, 通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符, 这被称为贪婪匹配.
- 匹配尽可能少的字符, 被称为懒惰匹配. 在限定符后面加上一个
?
- 相比贪婪与懒惰规则的优先级更高的: 最先开始的匹配拥有最高的优先权
1 | .*? # 代表了匹配任意数量的重复, 但是在能使整个匹配成功的前提下使用最少的重复. |
懒惰限定符 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
示例
1 | a.*?b # 匹配最短的, 以a开始, 以b最短的字符串 |
处理选项
如忽略大小写, 处理多行等, 这些选项能用来改变处理正则表达式的方式. 以下是**.Net**中常用的选项:
名称 | 说明 |
---|---|
IgnoreCase(忽略大小写) | 匹配时不区分大小写 |
Multiline(多行模式) | 更改^和$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.) |
Singleline(单行模式) | 更改.的含义,使它与每一个字符匹配(包括换行符\n) |
IgnorePatternWhitespace(忽略空白) | 忽略表达式中的非转义空白并启用由#标记的注释 |
平衡组/递归匹配(.Net支持)
- 匹配__(a(b))__的可嵌套的层次性结构, 使用**\(.+\)**只会匹配到最左边的括号和最右边的括号之间的内容.
1 | (?'group') # 把捕获的内容命名为group, 并压入堆栈(Stack) |
示例
- 把xx <aa
aa> yy
1 | < #最外层的左括号 |
- 常见的应用就是匹配HTML.
其他
语法 | 说明 |
---|---|
\a | 报警字符(打印它的效果是电脑嘀一声) |
\b | 通常是单词分界位置,但如果在字符类里使用代表退格 |
\t | 制表符,Tab |
\f | 换页符 |
\n | 换行符 |
\r | 回车 |
\A | 字符串开头(类似^,但不受处理多行选项的影响) |
\Z | 字符串结尾或行尾(不受处理多行选项的影响) |
\z | 字符串结尾(类似$,但不受处理多行选项的影响) |
\G | 当前搜索的开头 |