您的位置:首页 > 编程语言 > PHP开发

php-preg-1

2015-07-19 22:38 471 查看
正则表达式是由原子,元字符,模式修正三部分组成的。原子也就是普通字符。

基础

元字符:

\d: 匹配任意一个十进制数字[0-9]
\s: 匹配任何不可见字符,包括空格、制表符、换页符等等
\S: 匹配任意一个非空白字符。
\w: 匹配任意一个数字、字母、下划线[0-9a-zA-Z_]
. : 匹配除了换行符除外的任意一个字符


重复规则

?:匹配0次或一次
+:匹配1次或多次其前的原子
*:匹配任意次


其他:

|:匹配两个或多个分支选择,用来分隔多选一的模式
\b:匹配单词的边界
\B:非单词边界
^:匹配输入字符串的开始位置
$:匹配输入字符串的结束位置
():模式单元,将多个原子组成大的原子,当做一个单元。**这样会将相关匹配存储到一个缓存区中,可以被获取供以后使用。
存储子匹配的缓冲区编号从1开始,最大到99,每个缓冲区都可以使用\n来访问**。
在正则表达式模式中使用时注意转义。举个例子:”/^\d{4}(\W)\d{2}\\1\d{2}$/”。可以在括号中使用?:s设置非存储模式。


正则表达式引擎的内部工作机制

了解正则表达式引擎是如何工作的有助于你很快理解为何某个正则表达式不像你期望的那样工作。

两种类型的引擎:

1. 文本导向(text-directed)的引擎
2. 正则导向(regex-directed)的引擎。


Jeffrey Friedl把他们称作DFA和NFA引擎。本文谈到的是正则导向的引擎。这是因为一些非常有用的特性,如“惰性”量词(lazy quantifiers)和反向引用(backreferences),只能在正则导向的引擎中实现。所以毫无疑问这种引擎是目前最流行的引擎。

你可以轻易分辨出所使用的引擎是那种类型。如果反向引用或“惰性”量词被实现,则可以肯定你使用的引擎是正则导向的。可以作如下测试:

将正则表达式 /(regex|regex not)/ 应用到字符串“regex not”。如果匹配的结果是regex,则引擎是正则导向的。如果结果是regex not,则是文本导向的。

因为正则导向的引擎是“猴急”的,它会很急切的进行表功,报告它找到的第一个匹配 。正则导向的引擎总是返回最左边的匹配

这是需要你理解的很重要的一点:即使以后有可能发现一个“更好”的匹配,正则导向的引擎也总是返回最左边的匹配。


当把 /cat/ 应用到“He captured a catfish for his cat”,引擎先比较 c和“H”,结果失败了。于是引擎再比较 c 和“e”,也失败了。直到第四个字符,c匹配了“c”。a 匹配了第五个字符。到第六个字符 t 没能匹配“p”,也失败了。引擎再继续从第五个字符重新检查匹配性。直到第十五个字符开始,cat 匹配上了“catfish”中的“cat”,正则表达式引擎急切的返回第一个匹配的结果,而不会再继续查找是否有其他更好的匹配。

正则表达式的惰性

贪婪性

假设你想用一个正则表达式匹配一个HTML标签。这里就是指 <></> 之间的内容了。

首先可能会想到正则表达式 /<.+>/,但是你会发现,对于测试字符串 “This is a <EM>first</EM> test”,你可能期望首先会返回<EM>。

但事实是正则表达式将会匹配  <EM>first</EM>。很显然这不是我们想要的结果。原因在于+匹配符是贪婪的。也就是说,“+”会导致正则表达式引擎试图尽可能的重复前导字符。只有当这种重复会引起整个正则表达式匹配失败的情况下,引擎会进行回溯。也就是说,它会放弃最后一次的“重复”,然后处理正则表达式余下的部分。和“+”类似,“?*”的重复也是贪婪的。


深入正则表达式引擎内部

让我们来看看正则引擎如何匹配前面的例子。第一个记号是“<”,这是一个文字符号。第二个符号是“.”,匹配了字符“E”,然后“+”一直可以匹配其余的字符,直到一行的结束。然后到了换行符,匹配失败(“.”不匹配换行符)。于是引擎开始对下一个正则表达式符号进行匹配。也即试图匹配“>”。到目前为止,“<.+”已经匹配了“<EM>first</EM> test”。引擎会试图将“>”与换行符进行匹配,结果失败了。于是引擎进行回溯。结果是现在“<.+”匹配“<EM>first</EM> tes”。于是引擎将“>”与“t”进行匹配。显然还是会失败。这个过程继续,直到“<.+”匹配“<EM>first</EM”,“>”与“>”匹配。于是引擎找到了一个匹配“<EM>first</EM>”。
记住,正则导向的引擎是“急切的”,所以它会急着报告它找到的第一个匹配。而不是继续回溯,即使可能会有更好的匹配,例如“<EM>”。所以我们可以看到,由于“+”的贪婪性,使得正则表达式引擎返回了一个最左边的最长的匹配。


用懒惰性取代贪婪性

一个用于修正以上问题的可能方案是用“+”的惰性代替贪婪性。你可以在“+”后面紧跟一个问号“?”来达到这一点。“*”,“{}”和“?”表示的重复也可以用这个方案。因此在上面的例子中我们可以使用“<.+?>”。让我们再来看看正则表达式引擎的处理过程。

再一次,正则表达式记号“<”会匹配字符串的第一个“<”。下一个正则记号是“.”。这次是一个懒惰的“+”来重复上一个字符。这告诉正则引擎,尽可能少的重复上一个字符。因此引擎匹配“.”和字符“E”,然后用“>”匹配“M”,结果失败了。引擎会进行回溯,和上一个例子不同,因为是惰性重复,所以引擎是扩展惰性重复而不是减少,于是“<.+”现在被扩展为“<EM”。引擎继续匹配下一个记号“>”。这次得到了一个成功匹配。引擎于是报告“<EM>”是一个成功的匹配。整个过程大致如此。


惰性扩展的一个替代方案

我们还有一个更好的替代方案。可以用一个贪婪重复与一个取反字符集:“<[^>]+>”。之所以说这是一个更好的方案在于使用惰性重复时,引擎会在找到一个成功匹配前对每一个字符进行回溯。而使用取反字符集则不需要进行回溯。


最后要记住的是,本教程仅仅谈到的是正则导向的引擎。文本导向的引擎是不回溯的。但是同时他们也不支持惰性重复操作。

PHP群:45503780
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  php 正则