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

正则表达式学习之回溯与固态分组/php

2017-09-22 20:31 453 查看
在笔记回溯和固态分组时,先介绍什么是反向引用

//反向引用

//示例

$string = 'abcdebbcde';
$patern = '/([ab])\1/';
preg_match($patern, $string, $matchs);
var_dump($matchs);
//分析://对于'([ab])',是匹配'ab'中的一个字符,而\1则是反向引用了捕获数组中匹配的第一个字符,
//即是a或者b,而([ab])\1匹配的字符串则是 aa 或者 bb,但是在'abcdebbcde'中,第一个字符'a'满足要求,
//即由([ab])匹配'a'成功,将捕获的内容保存在下标为1的捕获数组中,然后将匹配编号为1的字符的权利交给了'\1'
//,所以这是([ab])\1匹配的内容为aa,但是由于第二个字符为'b',所以'aa'(\1)匹配失败,由于没有可供回溯的状态,
//所以整个表达式在 $string 位置0处匹配失败,所以继续从 $string 位置1(即是字符串的第二个字符)处继续匹配,以此直至传动到 $string 位置5时,
//([ab])\1成功匹配到 'bb',即是([ab])匹配的是b,而'\1'匹配的则是'b'.至此匹配结束.
//注意://在JavaScript中,由于浏览器解析引擎的不同,得到的结果也不一样,例如'\10'
//而在Firefox、Opera等浏览器中,“\10”被解析成第10个捕获组的反向引用
//而在.NET中,如果正则表达式加了RegexOptions.ECMAScript参数,则这里的“\10”被解析成第1个捕获组的反向引用加一个普通字符“0”。
//实例:
echo '<p>';
$string2 = 'abcc0aa0bb0';
$patern2 = '/([abc])\1(?:0)/';
$patern3 = '/([abc]\10)/';
preg_match($patern2, $string2, $matchs2);
var_dump($matchs2);

echo '<p>';
preg_match($patern3, $string2, $matchs3);
var_dump($matchs3);


//回溯

//示例:(和注释(学习笔记__可能有错误的地方))

echo "\n";
$string3 = 'abbcbbcdef';
//每一次'.+',都会留下一个回溯点
$patern4 = '/a.+c/';	//贪婪匹配,尽可能匹配满足要求的字符串最长(即是字符串越短越好),(实现方法:倒序回溯匹配),所以回溯了3次
preg_match($patern4, $string3, $matchs4);
var_dump($matchs4);
echo '<p>';
$patern5 = '/a.+?c/';	//懒惰匹配,尽可能匹配满足要求的字符串最短(即是字符串越短越好)(实现方法:正序回溯匹配),所以回溯了2次
preg_match($patern5, $string3, $match
9a4e
s5);
var_dump($matchs5);
//因此,回溯的效率和懒惰匹配和贪婪匹配没有关系,只是匹配的目标字符串长度不同


//固态分组:目的为了减少回溯次数
//示例:(有注释(学习笔记__可能有错误的地方))

//案例概述:比如要处理一批数据,原来格式为123.456,后来因为浮点数显示问题,部分数据格式变为123.456000000789这种,要求做到只保留小数点后面2-3位,但是,最后一位不能为0
echo '<p>';
$string4 = '123.456';
$patern1 = '/(\.\d\d[1-9]?)\d*/';
$patern2 = '/(\.\d\d[1-9]?)\d+/';

//patern1 和 patern2 ,相比之下,patern1如果处理的小数的小数位是3位的话,由于'*'匹配规则是一次或0次,会对字符在处理一次,而'+'则要求是1次或以上,所以对小数位为3位或者以上的话,能够简化匹配过程。

//然而简化匹配过程并不代表能够匹配到想要的结果,如果用$patern2 去匹配$string4的话,得到的结果将是123.45
//由于patern2至少要匹配长度为3的字符串,而'?'规则是匹配1或0次,那么当6匹配成功[1-9]后,'?'留下一个回溯点,
//'\d+'会继续匹配,由于‘6’以后没有字符了,所以放回到上一个回溯点,然后匹配'6'成功.所以捕获数组中'\\1'([1]的字符串)就是'.45';
//而没有实现我们想要的结果

//所以应用固化分组的特性,让'[1-9]?'一旦匹配成功就不能进行回溯了(因为'?'没有留下回溯点)
$patern3 = '/(\.\d\d(?>[1-9]?))\d+/';
$patern4 = '/(\.\d\d(?>[1-9]?))\d*/';

echo preg_match($patern3, $string4)? 1:0; //显然patern3匹配的结果是0(即是没有匹配到符合字符串)
echo '<p>';
echo preg_match($patern4, $string4)? 1:0; //而$patern4匹配的结果是1(说明匹配到了字符串);

echo '<p>';
//虽然patern3匹配失败但是也仅是限于3位或2位,而没有匹配成功也能达到保留3位或者两位的效果
//那么下面,我们将对第三位小数做讨论,当第三位小数位0时;
$string4 = '123.450';
echo preg_replace($patern3, '\\1', $string4);
echo '<p>';
echo preg_replace($patern4, '\\1', $string4);
echo '<p>';
echo preg_match($patern3, $string4, $matchs1);
echo '<p>';
echo preg_match($patern4, $string4, $matchs2);
echo '<p>';
var_dump($matchs1); //array(2) { [0]=> string(5) ".4501" [1]=> string(3) ".45" }
echo '<p>';
var_dump($matchs2); //array(2) { [0]=> string(5) ".4501" [1]=> string(3) ".45" }
//显然如果第三位小数为0,那么'\d+'就可以直接匹配'0',相比'\d*',省略一次匹配(因为是贪婪匹配,如果是懒惰匹配就不存在了);

//得出的结论就是,判断建议使用'\d*',替换建议使用'\d+';

//以上就是这一次学习的成果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: