为什么80%的码农都做不了架构师?>>>
一、php采用的是PCRE模式:
http://php.net/manual/zh/book.pcre.php
PCRE模式
二、常用函数
- preg_replace
执行正则表达式替换
http://php.net/manual/zh/function.preg-replace.php
preg_replace($pattern, $replacement, $string);
- preg_match
执行一次正则表达式匹配
$subject = "abcdef";
$pattern = '/^def/';
preg_match($pattern, $subject, $matches, PREG_OFFSET_CAPTURE, 3);
print_r($matches);
- preg_match_all
执行一个全局正则表达式匹配
preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject 直到到达结尾。 如果发生错误preg_match()返回 FALSE。
三、模式修饰符(匹配模式)
http://php.net/manual/zh/reference.pcre.pattern.modifiers.php
- i:大小写不敏感
- m:可跨行匹配,默认是不跨行匹配
- s:点号元字符可匹配换行符,默认点元字符是不匹配换行符
- U:这个修饰符逆转了量词的"贪婪"模式。 使量词默认为非贪婪的,通过量词后紧跟? 的方式可以使其成为贪婪的。这和 perl 是不兼容的。 它同样可以使用 模式内修饰符设置 (?U)进行设置, 或者在量词后以问号标记其非贪婪(比如.*?)
- u:模式字符串被认为是utf-8的,php 4.3.5 开始检查模式的 utf-8 合法性
- D:$元字符匹配结果中不包括换行符,默认模式是包括换行符的,设置成上面的m模式时会被忽略
- x:不常用,模式中的没有经过转义的或不在字符类中的空白数据字符总会被忽略
四、还有一些函数
- preg_replace_callback 执行一个正则表达式搜索并且使用一个回调进行替换
- preg_split 正则分割字符串为数组
五、子组(子模式)
- 字符集匹配 如果是字符集是多个字符组成,也叫字组(子模式),比如匹配apple和orange任意一个:
this is a (apple|orange)
//如果要否定子模式,则需要使用断言:前断言?!和后断言?
会匹配:this a apple、this a orange、this a ,可以匹配空字符
如果不需要捕获括符内容的话,在前面加上 ?:
即可,如果需要再加上内部选项设置,在 ?
和:
之间设置,一下写法作用是相同的
- 字组(子模式)命名 三种写法,后面两种需要版本>=php5.2.2支持:
(?Ppattern)
(?pattern)
(?'name'pattern)
- 多个子组可以共用一个后向引用数字
有个这样的问题,当我们这样用的时候:(?:(Sat)ur|(Sun))day
这里当后向引用 1 空时Sun 存储在后向引用 2 中. 当后向引用 2 不存在的时候 Sat 存储在后向引用 1中; 使用(?|
修改模式来修复这个问题:(?|(Sat)ur|(Sun))day
使用这个模式, Sun和Sat都会被存储到后向引用1中。
六、重复/量词
单字符量词
- * 等价于 {0,}
- + 等价于 {1,}
- ? 等价于 {0,1}
特殊用法:
- 量词紧跟着一个 ?(问号) 标记,它就会成为懒惰(非贪婪)模式,如果在模式修饰符中设置了
U
模式,量词后面加 ?(问号) 标记则成婪模式,就是和全局的匹配模式模式反着来。 - 量词紧跟着一个 +(加号) 标记,它会吃掉整个字符串
七、后向引用
-
在大于等于php5.2.2版本中采用 \g{1} 写法可以更好的理解,序列\1, \g1,\g{1} 之间是同义词关系,这种用法可以消除使用反斜线紧跟数值描述反向引用时候产生的歧义
-
\g 转义序列紧跟一个负数代表一个相对的后向引用。比如: (foo)(bar)\g{-1} 可以匹配字符串 ”foobarbar”, (foo)(bar)\g{1} 可以匹配 ”foobarfoo”。 这在长的模式中作为一个可选方案, 用来保持对之前一个特定子组的引用的子组序号的追踪。
-
后向引用也支持使用子组名称的语法方式描述, 比如 (?P=name) 或者 PHP 5.2.2 开始可以实用\k
或 \k'name'。 另外在 PHP 5.2.4 中加入了对\k{name} 和 \g{name} 的支持。
八、断言
- 前瞻性断言:只对它前面的字符生效
- 正面断言:以
(?=
开头 - 消极断言:以
(?!
开头
- 后瞻性断言:只对它后面的字符生效
- 正面断言:以
(?<=
开头 - 消极断言:以
(? 开头
九、条件子组
可以使匹配器根据一个断言的结果, 或者之前的一个捕获子组是否匹配来条件式的匹配一个子组或者在两个可选子组中选择。 条件子组的两种语法如下:
(?(condition)yes-pattern)
(?(condition)yes-pattern|no-pattern)
十、性能
Jeffrey Friedl 书(精通正则表达式)中包含了很多关于正则表达式性能的讨论。
- [aeiou] 这样的字符类会比可选路径 (a|e|i|o|u) 高效
- 模式匹配没有换行符的目标字符串,^.* 性能更佳
- (a+)b 比 (a+) 性能高,(a+)* 模式可以有 33 种方式匹配 ”aaaa”,它会尝试每种可能的变化,很消耗性能
十一、其他知识点
- 字符集匹配
单个可选分支是这样写,比如匹配abc中任意一个:
[abc]
如果是字符集是多个字符组成,也叫字组(子模式),比如匹配apple和orange任意一个:
this is a (apple|orange|)
会匹配:this a apple、this a orange、this a ,可以匹配空字符
如果不需要捕获括符内容的话,在前面加上 ?:
即可,如果需要再加上内部选项设置,在 ?
和:
之间设置,一下写法作用是相同的
(?i:saturday|sunday)
(?:(?i)saturday|sunday)
- 关于锚 ^ 元字符
正常情况下^
表示开头处,但是在字符集下,它代表反向(否定),比如下面表示不包含abc中任意一个字符
[^abc]
- 内部选项设置
默认的模式修饰符是全局的,但有些场景需要使用局部修饰符(也就说说局部模式修饰符),比如某部分匹配可以不区分大小写(默认是严格大小写区分的),使用方法为:(?修饰符)
apple (?iand) orange
以上会匹配apple and orange、apple And orange等等
参考:http://louiszhai.github.io/2016/06/13/regexp/