正则表达式


目录
  • 匹配单个字符
  • 匹配一组字符
  • 元字符
  • 重复匹配
  • 位置匹配
  • 子表达式
  • 反向引用
  • 环视
  • 嵌入式条件
  • 常见问题的正则表达式解决方案

匹配单个字符

字符:匹配普通文本,大小写敏感

.:除换行符外匹配任意单个字符(.:元字符)

\字符:对元字符进行转义,使其能够匹配本身,其中字符可以是多个连续的字符(\:元字符)

\.:匹配.本身,而不是匹配任意单个字符;\\:匹配\本身

匹配一组字符

[字符]:匹配字符集合内所有单个字符

-:连字符,用于[字符]定义字符区间,避免尾字符大于首字符,否则失效(-:在[]中为元字符,其他地方为普通字符,[]均为元字符)

[A-Za-z0-9]:匹配 A~Z、a~z、0~9 中的任意单个字符,-的前缀后缀遵循 ASCII 码顺序,例:[Z~a]:匹配 Z、[、\、]、^、_、`、a

[^字符]:排除匹配字符

[^0-9a-z]:排除匹配 0-9、a-z

元字符

元字符,具有特殊含义,部分在没有\转义时进行特殊匹配,部分在\转义时才进行特殊匹配

空白元字符 说明
[\b] 回退并删除一个字符(Backspace键)
\f 换页符
\n 换行符
\r 回车符
\t 制表符/水平制表符(Tab键)
\v 垂直制表符

文本行的结束标记:

  • Windows 系统:\r\n

  • Unix 及类 Unix 系统:\n

  • Mac 系统:\r

\r\n\r\n:匹配空白行(Windows)

数字元字符 说明
\d 任何一个数字字符[0-9]
\D 任何一个非数字字符[^0-9]
字母数字元字符 说明
\w 任何一个字母(大小写)数字字符或下划线字符[a-zA-Z0-9_]
\W 任何一个非字母(大小写)数字字符或下划线字符[^a-zA-Z0-9_]
空白字符元字符 说明
\s 任何一个空白字符[\f\n\r\t\v ]
\S 任何一个非空白字符[^\f\n\r\t\v ]

八、十六进制匹配:\x字符\0字符

不少正则表达式实现允许使用\c指定各种控制字符,例:\cZ匹配 Ctrl Z

POSIX字符类 说明
[:alnum:] 任何一个字母或数字[a-zA-Z0-9]
[:lower:] 任何一个小写字母[a-z]
[:upper:] 任何一个大写字母[A-Z]
[:alpha:] 任何一个字母[a-zA-Z]
[:xdigit:] 任何一个十六进制数字[a-fA-F0-9]
[:digit:] 任何一个数字[0-9]
[:blank:] 空格或制表符[\t ]
[:space:] 任何一个空白字符[\f\n\r\t\v ]
[:cntrl:] ASCII控制字符(ASCII 0~31、127)
[:punct:] 既不属于[:alnum:],也不属于[:cntrl:]的任何一个字符
[:graph:] 任何一个可打印字符,不包括空格
[:print:] 任何一个可打印字符

[[:digit:]]:匹配任何一个数字

JavaScript不支持正则表达式里使用 POSIX 字符

重复匹配

+(元字符)放置在某字符或字符集合后面则可以匹配其类型的1~n个字符

等价于{1,}[\w.]+等价于[\w\.]+,匹配字母、数字、下划线和 . 一次或多次,这里等价的原因是.+这样特殊的单个元字符在字符集合里面被视作普通字符

*(元字符)用法同上,匹配其类型的0~n个字符

?(元字符)用法同上,匹配其类型的0~1个字符

等价于{0,1}

{数字}用法同上,匹配其类型指定数量的字符;{数字1,数字2}用法同上,匹配其类型最少次数以及最多次数;{数字,}用法同上,匹配其类型最少次数,不限最多次数

\$匹配 $

living in AK and HI
匹配标签中的文本:
①<[Bb]>.*<\/[Bb]>
匹配结果:AK and HI
②<[Bb]>.*?<\/[Bb]>
匹配结果:AKHI

匹配 / 时,大多需要进行转义\/

原因在于+*是贪婪匹配,会从一段文本符合要求的开头匹配至末尾,保证尽可能多地匹配,而不是碰到第一个匹配时就停止,为了匹配尽可能少的字符,可在贪婪型匹配后面添加?,开启其懒惰模式

贪婪型 懒惰型
* *?
+ +?
{n,} {n,}?

位置匹配

\b匹配单词边界,即\w\W之间的位置、\w^之间的位置、\w$之间的位置

\bcat\b匹配单词 cat;\bcat匹配以 cat 开头的单词;cat\b匹配以 cat 结尾的单词

\<匹配单词开头,\>匹配单词结尾,但支持其使用的正则表达式引擎有限,一般不用

\B匹配非单词边界,与\b匹配效果相反

|I|'|d| | |prefer| |p2p| |O_O|
其中|表示位置,一个字符左右均为位置位,包括字符串开头结尾
\b可匹配的位置用#表示为:#I#'#d#  #prefer# #p2p# #O_O#
\B可匹配的位置用#表示为:I'd # p#r#e#f#e#r p#2#p O#_#O

字符串边界元字符:^匹配一行字符串起始位置(出现在字符集合里表示排除),$匹配一行字符串结束位置(多行文本在未开启多行模式的情况下,使用^$将只匹配第一行)

^\s*<\?xml.*\?>匹配 XML 文档头

(?m)启用多行模式,正则表达式引擎将\n视作字符串分割符,此时^$可匹配多行

(?m)^\s*\/\/.*$匹配 // 型注释

子表达式

 是 HTML 中不间断空格实体引用(即空格),若 {2,}则匹配  ;,把 ; 视作了子表达式(更长表达式的一部分),若要匹配整个表达式,则要使用(),这里即( ){2,},则匹配的部分是   

(\d{1,3}\.){3}\d{1,3}匹配 IP 地址(但不保证其数字不超过255,存在缺陷),若改为(\d{1,3}\.){3}(\d{1,3})不影响任何匹配,但根据具体的正则表达式实现,可能会影响性能

|为 OR(或)操作符

(19|20|21)\d{2}匹配以19、20、21开头的四位年份数字

(((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))\.){3}((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))匹配正确的 IP 地址,这里从规则的最后一项开始是因为若以规则第一项开始,会导致在第一项、第二项…均满足的情况下,只匹配第一项,而忽略所有后面的匹配项,即|匹配到则立马停止匹配剩余选择结构里面的其他模式从而导致更高优先级的匹配失效

12.159.46.200
(((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))\.){3}((25[0-5])|(2[0-4]\d)|(1\d{2})|(\d{1,2}))匹配12.159.46.200
(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))匹配12.159.46.20少了最后的0

有效的 IP 地址规则:

  • 任意的1位或2位数字
  • 任意的以1开头的3位数字
  • 任意的以2开头、第二位数字在0~4之间的3位数字
  • 任意的以25开头,第三位数字在0~5之间的3位数字

反向引用

引用已匹配的子表达式(用()括起来的部分,编号从1开始),\1表示引用第1个子表达式,依次是\2\3...分别引用第2个、第3个子表达式...,特殊的,\0代表整个正则表达式

<[Hh]([1-6])>.*?<[Hh]\1>匹配 HTML 标题(忽略任何不配对的标签)

部分正则表达式实现支持命名捕获(给某个表达式定义一个唯一的名称,随后用名称而不是相对位置,引用该子表达式以实现反向引用)

文本替换操作$反向引用对应下标(不同正则表达式引擎,指示符可能不同)

313-555-1234
248-555-9999
810-555-9000
(\d{3})-(\d{3})-(\d{4})//指定搜索模式
($1) $2-$3//指定替换模式
结果:
(313) 555-1234
(248) 555-9999
(810) 555-9000

大小写转换

元字符 说明
\E \L\U转换结束标志
\l 把下一个字符转换为小写
\L \L\E之间的字符全部转换为小写
\u 把下一个字符转换为大写
\U \U\E之间的字符全部转换为大写

Welcome to my homepage

(<[Hh]1>)(.*?)(<\/[Hh]1>) $1\U$2\E$3 结果:

WELCOME TO MY HOMEPAGE

环视

又称零宽度操作匹配,向前查看?=,向后查看?<=,具有返回结果(零长度字符串),向前查看模式长度可变,可以包含.+,而向后查看则一般为固定长度

正则表达式引擎支持任意一种查看,则支持对应的否定式向前?!、向后?查看

向前查看
http://www.forta.com
https://mail.forta.com
ftp://ftp.fotra.com
.+(?=:)
结果:
http
https
ftp

向后查看
ABC01: $23.45
HGG42: $5.31
CFMX1: $899.00
XTC9: $69.96
Total items found: 4
(?<=\$)[0-9.]+
结果:
23.45
5.31
899.00
69.96

否定式向后查看
I paid $30 for 100 apples,
50 oranges, and 60 pears.
I saved $5 on this order.
\b(?

嵌入式条件

反向引用条件:仅在一个前面的子表达式匹配的情况下允许使用另一个表达式

123-456-7890
(123)456-7890
(123)-456-7890
(123-456-7890
1234567890
123 456 7890
匹配要求:
123-456-7890
(123)456-7890
^(\()?\d{3}(?(1)\)|-)\d{3}-\d{4}

两种方式:

  • (?(反向引用)表达式)当且仅当反向引用匹配时,表达式求值
  • (?(反向引用)表达式1|表达式2)当反向引用成立时,表达式1求值,否则,表达式2求值

环视条件:将反向引用中的编号替换为环视表达式即可

11111
22222
33333-
44444-4444
匹配要求:
12345
12345-6789
类似的ZIP编码
\d{5}(?(?=-)-\d{4})	//如果前面存在-,则进行-\d{4}匹配
结果:
11111
22222
44444-4444

同样可使用 | 分别对成立与否的情况进行匹配

常见问题的正则表达式解决方案

URL:https?:\/\/[-\w.]+(:\d+)?(\/([\w\/.]*)?)?

不能处理查询字符串、用户名:密码部分

完整URL:https?:\/\/(\w*:\w*@)?[-\w.]+(:\d+)?(\/([\w\/.]*(\?\S+)?)?)?

越复杂的正则表达式执行速度越慢

http://www.forta.com/blog
https://www.forta.com:80//blog/index.cfm
http://www.forta.com
http://ben:password@www.forta.com/
http://localhost/index.php?ab=1&c=2
http://localhost:8500/
结果:
①
http://www.forta.com/blog
https://www.forta.com:80//blog/index.cfm
http://www.forta.com
http://ben
http://localhost/index.php
http://localhost:8500/
②
全部

电子邮件:(\w+\.)*\w+@(\w+\.)+[A-Za-z]+

HTML注释:

无法检测开始结束标签中连字符个数是否配对(连字符至少包含两个)