正则表达式可以用来从字符串中提取
和查找替换
字符
元字符 | 意义 |
---|---|
. |
点号,任意字符 |
[...] |
字符组,列出的任意字符 |
[^...] |
排除型字符组,未列出的任意字符 |
(...) |
组,添加 |
^ |
脱字符 行起始位置 |
$ |
美元符 行结束位置 |
\< |
反斜小于 单词起始位置 |
\> |
反斜大于 单词结束位置 |
` | ` |
+ |
之前紧邻的表达式 出现一次或者多次 |
* |
之前紧邻的表达式 出现零次或者多次 |
? |
之前紧邻的表达式 出现零次或者一次 |
*
和?
组成的对象在匹配成功的时候有可能匹配到的是空,既没有任何字符
排除型字符组也是一种匹配,既也需要匹配到内容
元字符 | 意义 |
---|---|
- |
[a-z] 连字符在字符组内部并且不处于头,表示范围 |
^ |
脱字符在字符组内部表示否定 |
. |
不是元字符 |
\元字符
匹配元字符代表的字符
\.
表示 匹配 .
计数量词 [a-z]{3} [a-z]{2,8}
量词 * + ? {min,max}
默认情况下都是贪婪(greedy)的,在匹配的过程中尽可能的匹配最多的内容。
忽略优先量词
一些工具提供了忽略优先量词 +? *? ?? {min,max}?
以去掉量词的贪婪性,在匹配的过程中尽量的匹配更少的内容。
占有优先量词
java等还提供了占有优先量词 ++ *+ ?+ {min,max}+
类似固化分组,一旦匹配成功,就不会交还匹配内容
.++ = (?>.+)
Perl和其他正则engine提供
shorthands | 意义 |
---|---|
\s |
匹配所有表示空白的字符,包括空格,制表符,换行符和回车符 |
\S |
[^\s] |
\t |
制表符 |
\n |
换行符 |
\r |
回车符 |
\w |
[a-zA-Z0-9] |
\W |
[^\w] |
\d |
[0-9] |
\D |
[^\d] |
引申到当前Local中
POSIX | 意义 |
---|---|
[:alnum:] |
字母字符和数字字符 |
[:alpha:] |
字母 |
[:blank:] |
空格和制表符 |
[:space:] |
所有空白字符,[:blank:]和换行符,回车符等 |
[:cntrl:] |
控制字符 |
[:digit:] |
数字 |
[:graph:] |
非空字符 |
[:lower:] |
小写字母 |
[:upper:] |
所有大写字母 |
[:punct:] |
标点符号 |
[:xdigit:] |
十六进制允许出现的数字 [0-9a-fA-F] |
修饰符 | 意义 |
---|---|
i |
ignore case |
g |
global,作用于在全局 |
x |
ingore space, comments after # |
s |
点号统配模式 |
m |
增强的行锚点模式 |
(?modifier) i,x,s,m 可以通过(?i)和(?-i)开启和关闭某种模式
如 <B>(?i)very(?-i)<B>
会对very进行不区分大小写匹配,但是还是区分大小些。
单行模式:.
不匹配换行符.
多行模式:修改了.
的匹配,.
匹配换行符。^``$
匹配内部换行符。
[\u4E00-\u9FA5]
允许表达式匹配与之前匹配相同的文本
([a-z])([0-9])\1\2
\1 表示匹配与第一捕获组 ([a-z]) 匹配到的相同的内容 \2 表示匹配与第二捕获组 ([0-9]) 匹配到的相同的内容
(?:...), like (?:abc) 查找到abc但是分组不捕获
(?if then |else) 如果if里面的内容为真,则执行then的子表达式,否则执行else的子表达式,常常和环视结合起来 (?(?<NUM:)\d+|\w+) 如果前面是NUM:则匹配一个数字,否则匹配一个字符
环视只匹配文本中的位置,不匹配任何字符.环视不消耗正则的匹配字符 顺序环视 (?=abc) 寻找找字符串中的一个位置,这个位置右边是abc 顺序否定环视 (?!abc) 寻找字符串中的一个位置,这个位置右边不是abc 逆序环视 (?<=abc) 寻找字符串中一个位置,这个位置左边是abc 逆序否定环视 (?<!abc) 寻找字符串中一个位置,这个位置左边不是abc 逆序环视通常只能匹配固定长度的内容,比如 (?<!book),不能变长如(?<!books?) 用环视解释一些特定正则缩写
\b 表示单词分解符,可以表示为寻找字符串中的一个位置,左边是单词,右边是非单词,或者左边是非单词,右边是单词
\b = (?<=\w)(?!=\w)|(?!<=\w)(?=\w)
password rule
(?=.*?[a-z])
: at this position in the string, we can match zero or more characters and a lower-case letter follow that.
#1 (?=.*?[A-Z])
: at this position in the string, we can match zero or more characters and an upper-case letter follow that.
#2 (?=.*?[0-9])
: at this position in the string, we can match zero or more characters and a digits follow that.
#3 (?![a-zA-Z0-9]+$)
: we need find a position that is NOT the following situation
, [a-zA-Z0-9]+$
a position followed by lower-case, upper-case,digits to the ends.
in another words, we find a position that followed by characters to ends, those characters are NOT all small-case, upper-case, digits, means include special characters.
all together, for a given string, during the pre-check cycle (pre-check does not change the position of regular engine), we can found position (one a same position) match the above three conditions.
^(?=.*?[a-z])(?=.*?[A-Z])(?=.*?[0-9])(?![a-zA-Z0-9]+$).{7,}$
enhancement ->
^(?=[^a-z]*?[a-z])(?=[^A-Z]*?[A-Z])(?=[^0-9]*?[0-9])(?![a-zA-Z0-9]+$).{7,}$
(?>...) 一旦匹配内容确定下来,就进行固化,并且排除其他备用选项,使得即使接下来的匹配失败,对于固话的分组无法进行回溯。 优点:1.快速失败,提高效率
^\w+: 匹配 subject
人类一眼能看出匹配失败,因为subject后面没有:
但是正则表达式需要用正则表达式的方法,NFA的话,表达式主导,\w+是优先匹配量词,所以会尽可能多的进行匹配,当匹配到't'的时候,已经存储了很多备用的状态,'t'之后匹配失败,会依次回溯,然后针对每一个状态再进行对':'的匹配,耗时且结果肯定是失败
^(?>\w+): 匹配 subject
固化\w+的捕获,优先占有量词会尽可能多的进行匹配,第一次检查':'的时候,\w已经匹配了所有的'subject',并且由于分组被固化,其他备用的状态都会被删除不能回溯,所以匹配很快会失败。
(?>.*?) 匹配什么
1. 忽略优先的匹配
2. 固化捕获
忽略优先导致.*?第一个尝试匹配成功的是空
*,+,?,{min,max}
总是尽可能多的匹配更多内容。只会影响匹配检测的顺序,不会影响匹配检测的路径(回溯路径)
"(.*)" 匹配
The name "McDonald's" is said "makudonarudo" in Japanese.
匹配结果 $1 = "McDonald's" is said "makudonarudo"
*?,+?,??,{min,max}?
量词匹配内容的时候,第一次匹配到内容就满足。只会影响匹配检测的顺序,不会影响匹配检测的路径(回溯路径)
"(.*?)" 匹配
The name "McDonald's" is said "makudonarudo" in Japanese.
匹配结果 $1 = "McDonald's"
notes: 在这个例子中也可以用 "[^"]*代替忽略优先量词,但是如果"是多字节字符,比如htmltag,可用否定环视
<B>
(
(?!</?B>) #后面不是<B>和</B>的任意字符
.
)* #
</B>
*+,++,?+,{min,max}+
用于固化优先匹配量词,使得优先匹配量词在匹配到内容后,放弃其他备选状态,在优先匹配量词匹配的内容范围内,无回溯。影响匹配检测的路径选择。
占有优先和固化捕获一样,不会影响匹配的顺序,但是会影响匹配路径的选择,让匹配无路可退。
NFA 正则表达式匹配多选结构是按照顺序执行的,只有前一个匹配失败才会回溯使用下一个匹配。所以 (ab)*|b
是没有意义的,因为 (ab)*永远能够匹配成功空。
sample 日期选择,一个月31天
1 2 3 4 5 6 7 8 9
01 02 03 04 05 06 07 08 09
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31
option #1 消除左下角多余,创建出正方形
31|[123]0|[012][1-9]
option #2 一行一行处理
3[01]|0?[1-9]|[12][0-9]
支持的元字符不同以及元字符的意义不同 POSIX将流派分为两种
- BRE basic regular expressions
不支持
+
,?
不支持多选结构 - ERE java extended regular expressions
引擎匹配执行流程总则
优先选择最左端的匹配结果
从当前位置测试整个正则表达式能匹配的文本,如果在当前位置测试了所有不可能的结果后还是找不到匹配结果,从当前位置的右边位置再继续标准匹配量词是匹配优先的
* ? + {min,max}
匹配的结果可能不是文本中最长的匹配文本, 但是他总是尝试匹配尽可能多的字符,直到匹配上线为止。
-
DFA 现代引擎,符合POSIX标准,egrep etc使用 不支持捕获括号和回溯(backreference) 确定型有穷自动机,搜索方式是
文本主导
,在预编译阶段会将正则表达式进行彻底分析并画出所有的可能路线,需要预编译时间长 -
NFA 传统型正则引擎,大部分程序采用。甄别方法,支持忽略优先量词 非确定型有穷自动机,搜索方式是
表达式主导
。预编译时间短,但是匹配的时候会通过回溯尝试所有的可能。NFA支持如下功能DFA不支持,回溯,分组捕获,忽略优先量词,有序多选结构,占有优先量词