正则表达式:快速入门
正则表达式:快速入门
元字符
分类
在正则表达式中,元字符是一类非常特殊的字符,它能够匹配一个位置或者字符集合中的一个字符。
分类:
- 匹配位置的元字符。
- 匹配字符的元字符。
匹配位置的元字符
说明:
实例:
匹配字符的元字符
说明:
实例:
·源文本:
1
a
A
?
***
·正则表达式
\W\W
·结果:
?
*
**
说明:
非单词字符包括换行符,所以A后面的换行符与?组合成目标串,一次类推。
字符类
说明
实例
说明:
如果字符类中包括-,即-也是字符类的一个元素,那么必须将其作为第一个字符。
如:[-a]表示匹配字符-或者字符a
字符转义
说明
实例
特别字符 |
在使用正则表达式时,如果需要匹配不在字符类指定范围内的字符时,可以使用反义规则。
在字符类中,如果^是字符类的第一个字符,则表示否定该字符类,即匹配除了该字符类以外的所有字符。
实例 [^-] 匹配除了连接符以外的所有字符
a[^b] 匹配字符a之后不是字符b的字符串
\B 匹配不是单词开头或结尾的任意位置
限定符说明正则表达式的元字符一次只能匹配一个位置或一个字符,如果要匹配0个,1个或多个字符时,需要使用限定符。
限定符用于指定允许特定字符或字符集自身重复出现的次数。
实例
贪婪与懒惰说明如果在限定符之后再添加一个字符"?",则表示尽可能少的重复字符?之前的限定符号的重复次数,这种匹配方式称为懒惰匹配。
贪婪匹配,仅仅使用单个限定符*、+、?、{n}、{n,}、{n,m}的匹配。
懒惰限定符
实例a.*b 贪婪匹配:匹配以a开头、以b结尾、最长的字符。
a.*?b 懒惰匹配:匹配以a开头、以b结尾、最短的字符。
a??b 使用0次重复或一次重复
替换说明如果要匹配区号为3位或4位的固定电话号码,可以使用替换满足需求。
最简单的替换使用“|”完成。
实例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位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔。你可以试试用分枝条件把这个表达式扩展成也支持4位区号的。
\d{5}-\d{4}|\d{5} 这个表达式用于匹配美国的邮政编码。美国邮编的规则是5位数字,或者用连字号间隔的9位数字。之所以要给出这个例子是因为它能说明一个问题:使用分枝条件时,要注意各个条件的顺序。如果你把它改成\d{5}|\d{5}-\d{4}的话,那么就只会匹配5位的邮编(以及9位邮编的前5位)。原因是匹配分枝条件时,将会从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了。
分组说明分组又称为子表达式,即把一个正则表达式的全部或部分分出一个或多个组。
分组使用的字符是"()"。
分组之后可以将()之内的表达式看成一个整体。
实例(\d{1,3}\.){3}\d{1,3} 匹配一个IP地址
后向引用说明当一个正则表达式被分组之后,每一个组会自动被赋予一个组号,该组号可以代表该组的表达式。
分组的编制规则:从左至右,以左括号为标志,第一个分组为1,第二个分组为2,以此类推。
反向引用提供了查找重复字符组的方便方法。它可被认为是再次匹配同一个字符串的快捷指令。
实例 \b(\w)\1\b 匹配具有两个重复字符的单词
\b(\w)(\d)\1\2\b 匹配一个字符和数字开头并重复该字符和数字的字符串
补充分组不但可以使用数字作为组号,也可以使用自定义名称作为组号。 (?<word>\w+) 将分组后的子表达式命名为word
(?'word'\w+) 将分组后的子表达式命名为word
更多分组
零宽断言说明接下来的四个用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。=
断言用来声明一个应该为真的事实。正则表达式中只有当断言为真时才会继续进行匹配。
实例
假如你想要给一个很长的数字中每三位间加一个逗号(当然是从右边加起了),你可以这样查找需要在前面和里面添加逗号的部分:((?<=\d)\d{3})+\b,用它对1234567890进行查找时结果是234567890。 下面这个例子同时使用了这两种断言: (?<=\s)\d+(?=\s) 匹配以空白符间隔的数字(再次强调,不包括这些空白符)。
负向零宽断言说明: 前面我们提到过怎么查找不是某个字符或不在某个字符类里的字符的方法(反义)。 但是如果我们只是想要确保某个字符没有出现,但并不想去匹配它时怎么办?例如,如果我们想查找这样的单词--它里面出现了字母q,但是q后面跟的不是字母u,我们可以尝试这样: \b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。 但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。 负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。 表达式(?!expression)又称为负向零宽度断言或者零宽度负预测先行断言,它断言自身位置的后名不能匹配字符串expression。
实例零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。 \d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;
\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
同理,我们可以用(?<!exp),零宽度负回顾后发断言来断言此位置的前面不能匹配表达式exp:(?<![a-z])\d{7}匹配前面不是小写字母的七位数字。 请详细分析表达式(?<=<(\w+)>).*(?=<\/\1>),这个表达式最能表现零宽断言的真正用途。 一个更复杂的例子:(?<=<(\w+)>).*(?=<\/\1>)匹配不包含属性的简单HTML标签内里的内容。(?<=<(\w+)>)指定了这样的前缀:被尖括号括起来的单词(比如可能是<b>),然后是.*(任意的字符串),最后是一个后缀(?=<\/\1>)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是<b>的话,后缀就是</b>了。整个表达式匹配的是<b>和</b>之间的内容(再次提醒,不包括前缀和后缀本身)。 |