关于正则表达式
正则表达式 (简称 regex 或 regexp)是用于描述搜索模式的特殊文本字符串。您可以将正则表达式视为类通配符。你可能熟悉通配符,例如 *.txt
,可在文件管理器中查找所有文本文件。正则表达式等效为 ^.*\.txt$
。但是你可以使用正则表达式执行更多操作,例如在文本编辑器类似 EditPad 或 Sublime 中,你可以使用 \b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b
搜索电子邮件地址,确切地说,是任何电子邮件地址。程序员则可以仅用一行代码来验证用户是否输入了正确的电子邮件地址,无论该代码是用 Perl, PHP, Java, .NET 语言还是更多的其他编程语言。
简单的例子
很可能你使用 Windows 系统查找某个 word 文档但又想不起名字,不妨试试通配符(wildcard),也就是 *
或 ?
加上 .docx
。
输入 *.docx
搜索结果会列出计算机或文件夹下的任何 word 文档
...
work.docx
data123.docx
XYZ.docx
demo.docx
word.docx
...
又或者你想查找某个文档只记得一部分文件名,可以使用 data*\.docx
其中 data 是你记忆的部分文件名。
搜索结果会列出计算机或文件夹内 data 开头的任何 word 文档
data123.docx
datax.docx
datay.docx
dataz.docx
datatoday.docx
尽管这种搜索方法很有用,但它还是有限的。通过理解 * 通配符的工作原理,引入了正则表达式所依赖的概念,但正则表达式功能更强大,而且更加灵活。
快速入门
显然,此文档无法解释关于正则表达式的所有知识,但是足以提高工作效率和出色完成日常工作。许多应用程序和编程语言都有自己的正则表达式实现过程,但是大多数桌面文档软件例如 excel、sublime 、notepad 等都支持正则表达式完成查找和替换工作。
如果我们要在支持正则表达式的文档编辑器中查找 word ,查找框直接输入word
其实就是最简单的正则表达式。但如果更复杂一些的情况,例如查找 do
,也许很不幸 doc
、dote
、doctor
… 都被列出,这不是我们想要的,这时需要调整搜索内容为\bdo\b
,其中两个\b
属于特殊字符(保留字符),它不匹配任何字符,仅界定英文单词的锚点。
特殊字符
因为我们要做的不仅仅是简单地搜索文字文本,所以我们需要保留某些字符以供特殊使用。
具有特殊含义的字符:反斜杠\
,脱字符^
,美元符号$
,点.
,竖线|
,问号?
,星号*
,加号+
,左括号(
,右括号)
,方括号[
和花括号{
,这些特殊字符通常称为 元字符 ,大多数时候它们不应该被单独使用。如果要将这些字符中的任何一个用在正则表达式中,则需要使用\
反斜杠对它们进行转义。
例如匹配 1+1=2 ,正确的正则表达式应为 1\+1=2
。否则,加号具有其他的特殊含义。
常用的元字符列表
字符 |
描述 |
\ |
将下一个字符标记为一个特殊字符、或一个原义字符。反向引用。 |
^ |
匹配输入字符串的开始位置。 |
$ |
匹配输入字符串的结束位置。 |
* |
匹配前面的子表达式零次或多次。例如,go* 能匹配 g 以及 gooo 。 |
+ |
匹配前面的子表达式一次或多次。例如,go 能匹配 goo 以及 gooo 。 |
? |
匹配前面的子表达式零次或一次。例如,do(es)? 可以匹配 do 或 does 。 |
. |
匹配除换行符 \n、\r 之外的任何单个字符。 |
x|y |
匹配 x 或 y。例如,`(g |
[xyz] |
字符集合。匹配所包含的任意一个字符。例如,[md] 可以匹配 god 中的 d 。 |
[^xyz] |
非字符集合。匹配未包含的任意字符。例如,[^md] 可以匹配 god 中的 g 和 o 。 |
[a-z] |
字符范围。匹配指定范围内的任意字符。例如,[1-3] 可以匹配 1、 2、 3。 |
[^a-z] |
非字符范围。匹配未包含的任意字符。例如,[^1-3] 可以匹配非 1、 2、 3 的任意字符。 |
\b |
匹配一个单词边界(不含任意字符)。例如,ye\b 可以匹配 eye 中的 ye ,但不能匹配 yes 中的 ye 。 |
\B |
匹配非单词边界(不含任意字符)。例如,ye\B 能匹配 yes 中的 ye ,但不能匹配 eye 中的 ye 。 |
\d |
匹配一个数字字符。等效于[0-9] |
\D |
匹配一个非数字字符。等效于[^0-9] 。 |
\n |
匹配一个换行符。等效于\x0a 或\cJ 。 |
\r |
匹配一个回车符。等效于\x0d 或\cM 。 |
\f |
匹配一个换页符。等效于\x0c 或\cL 。 |
\t |
匹配一个制表符。等效于\x09 或\cI 。 |
\v |
匹配一个垂直制表符。等效于\x0b 或\cK 。 |
\s |
匹配任何空白字符,包括空格、制表符、换页符等等。等效于[\f\n\r\t\v] 。 |
\S |
匹配任何非空白字符。等效于[^\f\n\r\t\v] 。 |
\w |
匹配字母、数字、下划线。等效于[A-Za-z0-9_] 。 |
\W |
匹配非字母、非数字、非下划线。等效于[^A-Za-z0-9_] 。 |
不可打印字符
可以使用特殊字符将不可打印字符放入正则表达式中。使用\t
匹配制表符,\r
表示回车,\n
表示换行。更多奇特的非可打印内容是\a
响铃,\ e
转义,\f
换页和\v
垂直制表符。它们的集合通常可以写成\s
等效于[^\f\n\r\t\v]
。
记住,Windows文本文件使用\r\n
终止行,而UNIX文本文件使用\n
结束行。
锚点示例
锚点是非常不一样的标记,它根本不匹配任何字符。而是匹配字符之前,之后或之间的位置。
脱字符^
匹配字符串中第一个字符之前的位置。应用^x
到 xyz 匹配一个 x ,^y
根本不匹配 xyz 中任何一个,因为 y 不在字符串的开头,^
匹配行首。同样,$匹配字符串中的最后一个字符。z$
匹配 xyz 中的 z ,单独使用$
不匹配任何文字。
如果需要限定的内容不在行首也不在最末的字符串,使用\b
是一个非常不错的选择,它们可用于固定某个边界位置。例如,z\b
匹配 xyz is abc
里面的 z ,\ba
匹配其中的 a 。也可以通过大写\B
写成a\B
反向匹配其中的 a 。
仅由锚组成的正则表达式只能找到零长度的匹配项。
轮换(等于或)示例
竖线|
轮换是等于或的正则表达式,由一个|
或者多个组成,类似这样cat|dog|ant
,匹配 cat、dog、ant或全部匹配。
例句:A cat and dog meets a group of cats and dogs.
需要匹配里面 cat、dog,一般情况,用cat|dog
和dog|cat
都行,但特殊时候,他们会有顺序要求。写成cat|dog
实际上不完美,因为一些复数单词将被截断,例如,dogs 和 cats,如果我们此时做替换,剩下 s 明显成为 bug 遗留下来,这个时候使用\b
锚点划定界限,写成\b(cat|dog)\b
,完美匹配 cat 和 dog,而 cats、dogs 不再部分匹配。
字符集合示例
要用字符集合匹配 a 或 e ,使用[ae]
即可。
可以在gr[ae]y
中使用它来匹配 gray 或 grey ,并不会匹配 graay 和 graey 这样的内容,因为字符集合本身仅匹配其中一个字符。
字符集合中字符的先后顺序无关紧要。
当然你也可以尝试其他集合,[0-9]
匹配 0 到 9 的任意一个数字,[a-z]
匹配 a 到 z 的任意一个字母。
速记字符示例
由于经常使用某些字符集合,因此可以使用一系列预定义的速记字符集合,通常可以理解为字符集合的简写形式。
\d
是[0-9]
的简写形式,\w
等效于[A-Za-z0-9_]
包含所有的文字字符即大写字母 A 到 Z 小写字母 a 到 z 数字 0 到 9 另外还有 _ (下划线)。\s
代表 空白字符 ,假设完整正则表达式支持时,它包含[\t\r\n\f]
,也就是匹配空格,制表符,回车符,换行符,换页符和垂直标签。
以上三个速记字符也具有否定形式,等效^
脱字符用法(可以称作反选字符集合或理解成排除字符集合)。
\D
与[^\d]
等效,匹配数字 0 到 9 之外 的任意字符。
\W
是[^\w]
的缩写,匹配所有大小写字母所有数字下划线 之外 的任意字符,比如.
、!
等等,以及空格符,换行符等等。
\S
和[^\s]
相同,匹配所有不可打印字符 之外 的任意字符。
万能匹配符示例
在正则表达式中,.
点是最常用的元字符之一,匹配(几乎)任何字符。点匹配任意单个字符,唯一的例外也许是换行符。在本文讨论的所有正则表达式中,默认情况下,.
点与\r\n
换行符都不匹配。它很强大,放上.
点来匹配,当您在有效数据上测试正则表达式时,一切都很好。问题是该正则表达式在不匹配的情况下也常常会匹配。
假设我们要匹配 mm/dd/yy 格式的日期,快速解决方案是\d\d.\d\d.\d\d
。起初看起来不错。它匹配的日期如 01/21/03 很好。问题是该正则表达式也将 02512703 视为有效日期。在此匹配中,第一个点匹配5,第二个点匹配7。显然不是我们想要的。
\d\d[- /.]\d\d[- /.]\d\d
才是更好的解决方案。此正则表达式使用[- /.]
字符集合包含有破折号、空格、点和正斜杠作为日期分隔符。此时字符集合(字符类)中的.
点不是元字符,因此我们不需要使用\
反斜杠对其进行转义。这个正则表达式其实还远远不够完善,它与99/99/99匹配为有效日期,这个问题能解决吗?答案是肯定的,文末会列出一系列常用且经过验证的正则表达式标准写法。
重复(量词)示例
?
问号使正则表达式中的前一个标记重复 0 次或 1次,实际上成为可选,colou?r
匹配 colour 和 color 。此时也可以使用{}
大括号匹配colou{0,1}r
,{0,1}
表示重复次数 0 次 或 1次。一般情况,colou{0,1}r
和colou?r
匹配相同内容。
通过使用括号将它们组合在一起,然后将?
问号放在右括号后面,可以使多个内容标记成为可选。例如,Nov(ember)?
匹配 Nov 和 November。
Feb(ruary)? 23(rd)?
匹配 February 23rd、February 23、Feb 23rd、和 Feb 23。
*
星号告诉表达式引擎尝试将之前内容标记匹配 0 次或更多次,+
加号则尝试 1 次或更多次匹配前面的内容。
Windows\d+
匹配 Windows 后面跟 1 个或更多数字,例如,Windows0、Windows7、Windows10、Windows3000等等,不能匹配 Windows,Windows\d*
匹配 Windows 以及Windows\d+
匹配的内容。为什么只是匹配 Windows 还有数字?别忘了,前面字符集合提到过\d
是[0-9]
的简写形式,而+
和*
重复了数字^v^。
还有一个附加的量词,可让指定重复多少次。语法为{min,max}
,其中 min 表示为最小匹配数量的正整数,max 表示为等于或大于 min 的正整数重复数量。如果存在逗号但省略了 max ,则最大匹配数量是无限的。因此{0,1}
与?
相同,{0,}
与*
相同,而{1,}
与+
相同。省略逗号和 max 相当于告诉表达式引擎准确的重复 min 的数量,例如,\b[1-9][0-9]{3}\b
来匹配 1000(含) 和 9999(含) 之间的数,\b[1-9][0-9]{2,4}\b
匹配 100(含) 到 99999(含) 之间的数字。
贪婪和懒惰示例
假设您要使用正则表达式来匹配 HTML 标签,并知道位于尖括号内的将是有效的 HTML 标签,例如有这样一段This is a <EM>first</EM> test
,因此正则表达式写成<.+>
,结果惊讶的发现匹配的是<EM>first</EM>
一整段,而并非需要的<EM>
和</EM>
这两段。原因很简单+
和*
都是贪婪的,当匹配了<
之后,会尽可能的寻找最后一个>
,要解决此问题借助问号,前面说过?
重复 0 次或 1 次,这里使用会使表达式变的懒惰,把正则表达式写成<.+?>
成功匹配到<EM>
和</EM>
。效率?如果需要匹配的数据量庞大,此时应该写成<[^>]+>
利用^
脱字符的排除特性达到懒惰目的。原因很简单<.+?>
从左到右解析,.+
会贪婪匹配最大范围直到?
出现再回退,而<[^>]+>
会匹配不是>
的内容,当第一个>
出现立刻停止,有效提高查询效率。
简单的讲贪婪和懒惰其实就是尽可能多匹配和尽可能少匹配。量词默认贪婪,加?
使其懒惰。
字符 |
描述 |
*? |
重复任意数量,但尽可能少重复。例如,g.*? 匹配 good 中的 g 。 |
+? |
重复1次或更多数量,但尽可能少重复。例如,g.+? 匹配 good 中的 go 。 |
?? |
重复0次或1次,但尽可能少重复。例如,g.?? 匹配 good 中的 g 。 |
{min,max}? |
重复 min 次到 max 次,但尽可能少重复。例如,g.{1,2}? 匹配 good 中的 go 。 |
{min,}? |
重复 min 次及以上,但尽可能少重复。例如,g.{0,}? 匹配 good 中的 g 。 |
分组和捕获示例
通过将正则表达式的一部分放在()
圆括号内就是分组,多个分组可以组合使用。Set(Value)?
匹配 Set 或 SetValue,这使得可以将量词应用到整个分组,或将替换限制为正则表达式的一部分。除了将正则表达式的片段分组在一起,括号还创建了一个分组编号。它在括号内存储与正则表达式部分匹配的字符串部分。
如果不需要该组来保存匹配项,则可以将此正则表达式优化为Set(?:Value)?
。左括号后的问?
号和:
冒号是创建非捕获组的语法。非捕获组可以通过|
轮换设定多个条件,例如,color=(?:red|green|blue)
这种形式,无需量词。
例如,13323366-027
,正则表达式(\b0\d{2,3}\b)-(\b\d{7,8}\b)
使其匹配并捕获到 2 组数据(区号)
和(电话)
不含-
,如果在sublime编辑器中,捕获的分组内容会被顺序赋予给$1
和$2
,替换值写成$2-$1
确认后,文本内容将变成 13323366-027
。
括号用于分组,方括号定义字符集合,量词使用大括号添加限定。
字符 |
描述 |
(exp) |
匹配exp,并捕获文本到自动命名的组里 |
(?:exp) |
匹配exp,不捕获匹配的文本 |
(?=exp) |
匹配exp前面的位置 |
(?<=exp) |
匹配exp后面的位置 |
(?!exp) |
匹配后面跟的不是exp的位置 |
(?<!exp) |
匹配前面不是exp的位置 |
反向引用示例
引用前面分组匹配的文本就是反向引用。假设要匹配一对 HTML 标签,以及两者之间的文本,通过将 HTML 标签的开始置于分组,标签的结束通过引用之前的分组捕获实现,使标签组成部分重用。
具体方法如下:<([A-Z][A-Z0-9]*)\b[^>]*>.*?</\1>
,此正则表达式仅包含一对括号,它们由[A-Z][A-Z0-9]*
部分捕获内容,反向引用标记\1
(反斜杠)引用第一个捕获分组。\1
匹配第一个捕获组所匹配的完全相同的文本,并将/
放在\1
之前,因为它是 HTML 结束标记的特征。
要找出引用的编号,请从左到右扫描正则表达式,第一个括号\1
,第二个\2
,以此类推。
可以多次重复使用相同的反向引用,([xy])z\1z\1
匹配 xzxzx 或 yzyzy 。大多数正则表达式版本支持最多\99
个捕获分组编号。
零长度断言示例
零长度断言可以简单的理解成环视周围,假如你寻找钱包,有人告诉你的 钱包 在 香烟 旁边,你拿走了 钱包 没有理会 香烟 。
既然是只环视周围,从平面文本 football 来看,即 ball 的左边或者 foot 的右边,由正则表达式标记?=
和?<=
区分。条件\b\w+(?=ball)
匹配 foot (?<=foot)\w+\b
匹配 ball。文本 I like volleyball and football. 使用\b\w+(?=ball)
成功匹配 volley 和 foot。
那为什么是零长度呢?去掉\b\w+
部分,仅保留(?=ball)
尝试替换成&
会发现文本变成了foot&ball
,原本foot 和 ball 之间确实零长度,该过程没有替换任何字符而是 插入 。
前面成功找到了 香烟 旁边的钱包,但事情如果更复杂些,有多个 钱包 并且已知红色钱包不要,其他都要。这里可以用负环视(这里可以简单理解成反选),只需把?=
和?<=
替换成?!
和?<!
即可。
例子:
\b\w+(?<!y)ball\b
仅匹配 football, basketball and volleyball. 中的 football 和 basketball。
\bgood(?!b)\w+\b
仅匹配 goodbye goodtime. 中的 goodtime。
正则表达式实例样本
正则表达式非常强大,确实需要一些时间来学习。但是,学习和使用 sublime 或 EditPad 编辑示例,可以迅速入门。之后在多种语言编写脚本或应用程序将很快赚回正则表达式学习时间。在下面,有一些标准示例,可用于适配使用目的。
不准备成为程序员当然也可以学习正则表达式,正则表达式无处不在 ^.*!
抓取HTML标签
<TEST\b[^>]*>(.*?)</TEST>
匹配指定 HTML 标记的开头和结尾,正则表达式中的问号使*
变得懒惰。此正则表达式无法匹配嵌套在 HTML 标签内部的标签例如,<H1>I'm<em>very</em>good</H1>
里面的一对 <em></em>
标签。
<([A-Z][A-Z0-9]*)\b[^>]*>(.*?)</\1>
将匹配任何 HTML标记的开头和结尾,HTML 区分大小写。该解决方案的关键是在正则表达式中使用反向引用\1
分组内容到 HTML 结束标记。该解决方案也将不匹配嵌套里面的 HTML 标签。
修剪空白
通过正则表达式搜索和替换,可以轻松地从文本文件中字符串或行的开头和结尾修剪掉不必要的空格。
搜索^[\t]+
并替换为空删除行首空白(空白制表符如 Tab )。搜索[\t]+$
以修剪行尾。
通过将正则表达式组合成^[\t]+|[\t]+$
来完成以上两者。想去除换行符,也可以展开字符类输入[\t\r\n]
或改用简写\s
。
数字匹配
由于正则表达式处理文本而不是数字,因此在给定范围内匹配数字时需要注意。你不能只是写[0-255]
去匹配 0 和 255 之间的数字,虽然这是有效的正则表达式,它匹配完全不同的东西。正则表达式只认识单个字符,以上表达式被拆分成 匹配 0-2 之间的数字 另外匹配 5 再匹配一个 5 ,仅匹配含单个数字 0 1 2 5 。
匹配 0-255 需要观察[0-9]
匹配个位数 0-9,[1-9][0-9]
匹配 10-99 的两位数,三位数需要排除 256-999 变得复杂,通过1[0-9][0-9]
匹配 100-199,用2[0-4][0-9]
匹配 200-249,剩下25[0-5]
匹配 250-255。
通过轮换得到完整正则表达式\b[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]\b
,并用2个\b
锚点定义边界。
常见的数字匹配范围
字符 |
描述 |
000-255 |
`^([01][0-9][0-9] |
0、00、000-255 |
`^([01]?[0-9]?[0-9] |
0-999 |
`^([0-9] |
000-999 |
^[0-9]{3}$ |
0、00、000-999 |
^[0-9]{1,3}$ |
001-999 |
`^(00[1-9] |
1、01、001-999: |
`^(0{0,2}[1-9] |
浮点匹配
创建正则表达式时,考虑不应该匹配的内容比应匹配的内容更为重要,比如转义一个正确的\.
小数点,而不是误写成.
虽然包含正确的小数点,但同时也包含了非数字的其他内容,比如正确匹配 3.14 的同时也匹配 3x14、3y14等等。
正确的表达式应写成[-+]?[0-9]*\.?[0-9]+
,匹配所有的正数含浮点数,负数含浮点数。
匹配电子邮件
\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b
上面的正则表达式的优点在于,它与当今使用的99%的电子邮件地址匹配,如需区分大小写请加入 a-z 。
\b[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}\b
当然也可以根据实际清空更换边界符^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$
。
匹配有效日期
假设从1900年01月01日到2099年12月31日,匹配yyyy-mm-dd格式,写成以下表达式。
^(19|20)\d\d[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$
其中年4位,月2位,日2位,- 和 . 作为年月日的分隔符。要真正做到完美,必须将月份分为多个选项,以考虑月份的长短。上面的正则表达式也匹配2003-02-31和2003-02.31,这不是有效日期。要使分隔符保存一致,可使用以下表达式。
^(19|20)\d\d([- /.])(0[1-9]|1[012])\2(0[1-9]|[12][0-9]|3[01])$
闰年是公历中的名词。闰年分为普通闰年和世纪闰年。普通闰年:公历年份是4的倍数的,且不是100的倍数,为闰年;世纪闰年:公历年份是整百数的,必须是400的倍数才是世纪闰年(如1900年不是世纪闰年,2000年是世纪闰年);公历中只分闰年和平年,平年有365天,而闰年有366天(2月中多一天)。
用脚本语言更容易排除某一年没有2月29日。与使用正则表达式相比,使用简单的算术检查一年是否可以被4整除,除非被400整除,否则不能被100整除要容易得多。
sub isvaliddate {
my $input = shift;
if ($input =~ m!^((?:19|20)\d\d)[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$!) {
# At this point, $1 holds the year, $2 the month and $3 the day of the date entered
if ($3 == 31 and ($2 == 4 or $2 == 6 or $2 == 9 or $2 == 11)) {
return 0; # 31st of a month with 30 days
} elsif ($3 >= 30 and $2 == 2) {
return 0; # February 30th or 31st
} elsif ($2 == 2 and $3 == 29 and not ($1 % 4 == 0 and ($1 % 100 != 0 or $1 % 400 == 0))) {
return 0; # February 29th outside a leap year
} else {
return 1; # Valid date
}
} else {
return 0; # Not a date
}
}
如果匹配mm/dd/yyyy格式, 表达式应改写成以下格式。
^(0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])[- /.](19|20)\d\d$
匹配dd-mm-yyyy格式,修改表达式为以下格式。
^(0[1-9]|[12][0-9]|3[01])[- /.](0[1-9]|1[012])[- /.](19|20)\d\d$
查找或验证IP地址
匹配IP地址是正则表达式复杂性和准确性之间一个很好的例子。\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b
可以匹配任何IP地址,但也将匹配 999.999.999.999 这样看似有效的IP地址。正确的IPV4规定的IP地址应该由 4 段组成,且每一段只能是 0-255 之间的数字。
\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
这可能看起来有些长,实际由 4 段(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.
组成,最后一段去掉\.
点,前后加上\b
锚点作为边界。
很明显,上面一段表达式可以匹配 0 开头的数字例如 01.02.023.056,虽然很多时候不影响使用,如果看不顺眼可以修改表达式让其消失。
\b(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b
同样,不要看起来表达式有些长,实际上主体只有(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.
,第四段别忘记去掉\.
点。如果不需要单独捕获IP地址 4 段中的每一段,可以{3}
重复字符缩写成以下表达式。
\b(?:\d{1,3}\.){3}\d{1,3}\b
\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b
\b(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\b
删除整行文本
希望通过查找部分文本,但又不限于该文本,而是包含整行,然后在文本编辑器中的搜索和替换删除整行,这将很有用。为了使此示例简单,假设我们要匹配包含单词 good 的行。正则表达式查找 good 很容易,但是软件只会将 good 标记匹配,而不是包含单词的整行。
解决方案非常简单,^.*good.*$
。为了指定整行,将^
脱字符号和$
启用,原始表达式 good 包含进去,之前和之后的各个部分使用点和星号即可。
如果 good、great、fine 多个条件中的其中一个满足则匹配整行,可以使用|
轮换改写表达式为^.*\b(good|great|fine)\b.*$
,正如所见的,使用轮换时,需要使用()
括号将表达式分组。为了避免在不同环境中.*
的贪婪,建议加上?
使其懒惰,改变正则表达式为^.*?\b(good|great|fine)\b.*$
如果要求同时满足所有条件,则应该使用零长度断言(环视),正则表达式写作^(?=.*?\bgood\b)(?=.*?\bgreat\b)(?=.*?\bfine\b).*$
,通过?=
指定必须满足的条件,达到多条件同时匹配,正则表达式环境要求.
点必须不与换行符匹配。类似\bgood\b
这样的表达式,无论它多么复杂,都可以使用环视替代,.*$
在先确定满足条件后,使正则表达式与该行匹配。
如果条件是匹配不包含单词 good 的整行,则使用负环视,表达式写成^((?!good).)*$
,和之前不同,为了让不同地方的 good 捕获成功,需要表达式更为积极,不应使其?
懒惰和限制首尾之外的\b
单词边界锚点。
删除重复内容
假如文档中很多行单词,只需先将其排序使,然后使用^(.*)(\r?\n\1)+$
根据不同编辑器替换成\1
或$1
即可。边界锚点需要在换行符之前和之后匹配,而不仅仅是字符串的开头和结尾,并且点必须不与换行符匹配。
然后可以将以上示例扩展为从字符串中删除重复项,比如要从逗号分隔的列表中删除连续的重复项,可以使用(?<=,|^)([^,]*)(,\1)+(?=,|$)
。
其中(?<=,|^)
正则表达式引擎描述开始或逗号之后开始匹配,([^,]*)
捕获内容。(,\1)+
匹配连续的重复内容。最后(?=,|$)
通过检查逗号或字符串结尾来检查重复项是否为完整。
寻找之间
使用正则表达式,您几乎可以描述任何文本模式,包括将两个单词或标记之间的匹配。此模式相对简单,由三个部分组成:1.第一个单词或标记,2.一定数量的未指定的单词或字符,3.第二个单词。未指定的单词可以用速记字符\w+
匹配,其他空格和其他字符可以用\W+
匹配,注意是大写 W 。
假如匹配 wordx 到 wordy 之间,使用:\bwordx\W+(?:\w+\W+).*wordy\b
即可。为了尽可能避免贪婪,请替换量词.*
为{1,6}?
或..*?
这种形式。
如果单词也可能以相反的顺序出现,还需要指定相反的模式:
\b(?:wordx\W+(?:\w+\W+){1,6}?wordy|wordy\W+(?:\w+\W+){1,6}?wordx)\b
如果要从单词列表中找到任意两个单词之间,可以使用:
\b(wordx|wordy|wordz)(?:\W+\w+){1,6}?\W+(wordx|wordy|wordz)\b
。此正则表达式还将在自身附近找到一个单词,例如,它将与 wordz 附近的 wordz 匹配。
正则表达式进阶
如今,有许多应用程序以各种方式支持正则表达式,从而增强了其些功能。正如本文开头所说,不同的编程语言略有差异。但是,某些应用程序通过功能全面的Perl风格实现的正则表达式脱颖而出,并允许在整个应用程序中使用正则表达式代替文字搜索项。
当然你可以选择自己熟悉的编程语言进阶,例如:Boost,Delphi,GNU (Linux),Groovy,Java,JavaScript,.NET,PCRE (C/C++),PCRE2 (C/C++),Perl,PHP,POSIX,PowerShell,Python,R,Ruby,stdregex,Tcl,VBScript,Visual Basic 6,wxWidgets,XML Schema,Xojo,XQuery&XPath,XRegExp… 当然还有数据库 MySQL,Oracle,PostgreSQL…
专用工具
grep - 来自 UNIX 世界的实用程序,它首先使正则表达式流行。
PowerGREP - 适用于 Microsoft Windows 的下一代 grep。
RegexBuddy - 学习,创建,理解,测试,使用和保存正则表达式。RegexBuddy 使正则表达式的使用比以往更加轻松。
RegexMagic - 使用 RegexMagic 的强大模式而不是神秘的正则表达式语法来生成正则表达式。