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

在笔记回溯和固态分组时,先介绍什么是反向引用

//反向引用
//示例

$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, $matchs5);
	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+';

//以上就是这一次学习的成果


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值