《正则表达式30分钟入门教程》笔记
寒假时做的笔记,现转发到这里。
原文请见此处
本文介绍的是 .Net Framework 4.x 下的正则表达式,但大部分语法可以通用。
入门
假设你在一篇英文小说里查找hi,你可以使用正则表达式hi。通常,处理正则表达式的工具会提供一个忽略大小写的选项,如果选中了这个选项,它可以匹配 hi,HI,Hi,hI 这四种情况中的任意一种。
但hi这个表达式会匹配到包含hi的其他单词,如 him, history, high 等等。如果只想匹配 hi 这个词,需要使用\bhi\b。
\b匹配这样的位置:它的前一个字符和后一个字符不全是\w。\b并不表示单词分隔符,尽管看起来的效果确实如此。
\b是一个元字符(metacharacter)。
*也是元字符,它代表的是数量——它指定*前边的内容可以连续重复使用任意次。
.也是元字符,匹配除了换行符'\n'以外的任意字符。
于是,.*就表示任意数量的非换行符。
假如要匹配hi后面不远处跟着一个Lucy,则可用\bhi\b.*Lucy。
元字符\d匹配一位数字(0-9)。如\d\d\d\d表示一个4位的数字。为了简洁,上面的表达式可以简写为\d{4},表示\d要连续匹配4次。而\d{5,12}表示重复的次数不能少于5次,且不能多于12次。
元字符
对中文的特殊处理是由 .Net 正则表达式引擎支持的,不是标准内容。
\s匹配 任意的空白符。这里的空白符指空格,Tab,'\n'和中文全角空格等。
\w匹配 字母或数字或下划线或汉字。
+与*类似,不同的是*允许重复任意次(包括0次),而+允许重复1次或更多次。
^匹配 字符串的开始。它匹配位置,下面的$也一样。
$匹配 字符串的结束。
上面两个元字符常常用于验证输入的内容。比如匹配一个5-12位的QQ号,可用^\d{5,12}$。
一些例子:
\ba\w*\b 匹配以a开头的单词。这里的单词是指不少于一个的连续的\w。
\d+ 匹配1个或更多连续的数字。
\b\w{6}\b匹配刚好6个字符的单词。
字符转义
要查找\这个字符本身,应使用\\。
要查找.这个字符本身,应使用\.。
其他类同。
重复
正则表达式中所有的限定符(即用于指定数量的代码):
| 代码/语法 | 说明 |
|---|---|
* |
重复零次或更多次 |
+ |
重复一次或更多次 |
? |
重复零次或一次 |
{n} |
重复n次 |
{n,} |
重复n次或更多次 |
{n,m} |
重复n到m次 |
字符类
想要匹配数字、空白等的集合是容易的,因为已经有对应的元字符。如果想要匹配字母的集合,可以在方括号里列出所有备选的字母。如[aeiou]匹配任何一个英文元音字母,[.?!]匹配三种标点中的任何一个。
也可以指定字符范围,如[0-9]等价于\d,而在纯英文场景下,[a-z0-9A-Z]等价于\w。
注意[]中的字符不能用空格分隔。如果用了空格,则空格也会被匹配。
分枝条件
正则表达式里的分枝条件指的是有几种规则,如果满足其中任意一种规则都应该当成匹配,具体方法是用|把不同的规则分隔开。
0\d{2}-\d{8}|0\d{3}-\d{7}这个表达式能匹配两种以连字号分隔的电话号码:一种是三位区号,8位本地号(如010-12345678),一种是4位区号,7位本地号(0376-2233445)。
\(0\d{2}\)[- ]?\d{8}|0\d{2}[- ]?\d{8}这个表达式匹配3位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。
使用分枝条件时,要注意各个条件的顺序。例如\d{5}-\d{4}|\d{5}和\d{5}|\d{5}-\d{4}匹配的是不同的模式,因为分枝条件总是从左向右匹配,后者的前一个条件会涵盖后一个条件的全部情况。
分组
表示重复的单个字符是容易的:只需要在该字符后面加限定符即可;如果想要表示重复的多个字符,则需要用小括号指定子表达式(又名 分组)。
(\d{1,3}\.){3}\d{1,3} 是一个简单的IPv4匹配表达式。注意IPv4允许前导0。这个表达式有个缺陷,就是它会匹配类似256.300.888.999这种不合法的地址。
标准的Ipv4匹配表达式是((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)。
反义
若想查找除了数字以外,其它任意字符都行的情况,这时需要用到反义。
| 代码/语法 | 说明 |
|---|---|
\W |
匹配任意不是字母、数字、下划线和汉字的字符 |
\S |
匹配任意不是空白的字符 |
\D |
匹配任意非数字的字符 |
\B |
匹配不是单词开头或结束的位置 |
[^x] |
匹配除了x以外的任意字符 |
[^aeiou] |
匹配除了aeiou这几个字母以外的任意字符 |
后向引用
使用小括号指定一个分组后,每个分组会自动拥有一个组号,规则如下:
- 分组0对应整个正则表达式
- 从左向右扫描整个表达式,以分组的左括号为准,第一个分组为1,第二个分组为2,依此类推。这样的扫描进行两遍,第一遍只给未命名组分配,第二遍只给命名组分配。
- 可以使用
(?:exp)这样的语法来剥夺一个分组对组号分配的参与权。
后向引用用于重复搜索前面某个分组匹配到的文本。如\1表示分组1匹配到的文本。
例子:
表达式\b(\w+)\b\s+\1\b用来匹配重复的单词,如go go或kitty kitty。其中\b(\w+)\b表示一个单词,这个单词被捕获到编号为1的分组中。然后跟1个或更多空白字符(\s+),最后还是分组1捕获到的内容(\1)。
也可以手动指定子表达式的组名。语法为(?<Word>\w+),或将尖括号换成':(?'Word'\w+)。这样这个分组的组名就变成Word。上面例子中的表达式变成\b(?<Word>\w+)\b\s+\k<Word>\b。
常用分组语法
(exp)匹配exp,并捕获文本到自动命名的组里。(?<name>exp)匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp)。(?:exp)匹配exp,但不捕获匹配的文本,也不给此分组分配组号。(?=exp)零宽断言。匹配exp前面的位置。(<=exp)零宽断言。匹配exp后面的位置。(?!exp)零宽断言。匹配后面跟的不是exp的位置。(?<!exp)零宽断言。匹配前面不是exp的位置。(?#comment)注释。这种分组没有任何实际意义,仅仅用于注释。
零宽断言
(?=exp)又名零宽度正预测先行断言,它断言自身出现的位置的后面能匹配表达式exp。比如\b\w+(?=ing\b)匹配以ing结尾的单词的前面部分。如对字符串I'm singing while you are dancing应用该表达式,将匹配sing和danc。
(?<=exp)又名零宽度正回顾后发断言,它断言自身出现的位置的前面能匹配表达式。比如(?<=\bre)\w+\b会匹配以re开头的单词的后半部分。
负向零宽断言
零宽度负预测先行断言(?!exp)断言此位置的后面不能匹配表达式exp。例如\d{3}(?!)匹配三位数字,且这三位数字的后面不能是数字。
零宽度负回顾后发断言(?<!exp)断言此位置的前面不能匹配表达式exp。例如(?<![a-z])\d{7}匹配前面不是小写字母的7位数字。
一个更加复杂的例子:表达式(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。它不匹配标签本身。
注释
如果想要包含注释,最好启用“忽略模式里的空白符”选项,这样在编写表达式时可以任意的添加空格,Tab或换行,这些空格将被自动忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:
(?<= # 断言要匹配的文本的前缀
<(\w+)> # 查找尖括号括起来的内容
# (即HTML/XML标签)
) # 前缀结束
.* # 匹配任意文本
(?= # 断言要匹配的文本的后缀
<\/\1> # 查找尖括号括起来的内容
# 查找尖括号括起来的内容
) # 后缀结束
贪婪与懒惰
正则表达式中包含能接受重复的限定符时,通常的行为是匹配尽可能多的字符。如a.*b将会匹配最长的以a开始,以b结束的字符串。这称为贪婪匹配。
有时我们需要于此相反的懒惰匹配,前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。于是,a.*?b就表示最短的以a开始,以b结束的字符串。
例如,对于字符串aabab,a.*b将匹配整个字符串,a.*?b将匹配aab和ab。
| 代码/语法 | 说明 |
|---|---|
*? |
重复任意次,但尽可能少重复 |
+? |
重复1次或更多次,但尽可能少重复 |
?? |
重复0次或1次,但尽可能少重复 |
{n,m}? |
重复n到m次,但尽可能少重复 |
{n,}? |
重复n次以上,但尽可能少重复 |

浙公网安备 33010602011771号