周末记事-还是我的老爷机

我的老爷机:
06年买的主机箱+飞利浦CRT显示器,07年更换电源风扇,08年上半年分别更换了主板,硬盘,下面年,在内存最低价的时候,99块包快递买了DDR2 667的内存条一根,更新了老内存。09年再次更换了电源风扇,10年由于换地方住,搬家,桌子太靠墙,CRT大屁股显示器放不下,买了优派的22寸液晶显示器,鸟枪换炮了,哈。CRT显示器忍痛割爱以50元的价格卖给了小贩,哎,心痛。接着,鼠标又不灵了,更换了鼠标。从06年坚守到现在的器件只有CPU、主机箱、显卡,光驱、键盘了。

昨天晚上,10点半左右,老爷机又突然间罢工了,顿时,我心急如焚呀,心想即将到来的周末,作为宅男,我不能接受。赶紧调试吧。首先,我以为是天气太热,导致CPU温度过高,激活主板自动保护策略,强制关机的。赶紧把CPU风扇拿出来,放到空调边吹了会,装上去之后,开机,还是不行,主板灯亮了,但是CPU风扇不转,而且,电源也没反映,我愕然了,难道电源又坏了不成?好吧,我认输,周末再说吧,睡觉。

前序:
在老爷机罢工之前,一群内网友求助正则匹配html标签中 table之间的内容,要发现的第一个table之间的内容。字符串大约为

<table class="t1 t2"><tr><td><table class="t1 t2">sssssssssssssssss</table></td></tr><tr>
<td><table class="t1 t2">ss
sssssssssssssss</table></td></tr></table>

同学A提供【<table[\s\S]*</table>】(具体记不清了,大体是这个)

这个正则的匹配结果是不能满足其要求的,很明显,【*】为量词优先,导致贪婪匹配把后面最后一个</table>之前的字符串全部匹配进去了。

见截图:

A同学提供的不严谨的正则表达式

接着,另外以为网友提到,后面加U修饰符。对于这个正则,对于这个要求,加U修饰符能达到目的吗? 答案是可以的。为什么?这种方式可靠吗?有风险吗?有其他方法吗?

先来解释一下U(大写字母U,非小写,小写的是uincode字符模式)是干吗的? 是对“匹配优先量词(贪婪)”与“忽略优先量词(非贪婪)”的取反,也就是说,原来是【*】、【+】的,会按照【*?】、【+?】来执行,如果是【*?】、【+?】的,则按照【*】、【+】来执行,这个修饰符很怪,很乱,如果正则为【\w+】,为了达到“非贪婪匹配”,使用了修饰符U。过几天,你修改了这个正则,修改为【\w+\s+?】,你的本意是在原来的基础上,加上非贪婪的空白字符的匹配,可是,后面的大写字母U修饰符也对你前面的非贪婪取反了,从而,导致匹配错误,所以,建议大家不要使用大写字母的U修饰符,直接在表达式里写好贪婪还是非贪婪。

我的答案是【<table[^>]+?>(?>((?!</table>).(?<!<table))+)</table>】。

我靠,你这这什么玩意?这么乱?这是什么意思?

解释一下:

  1. 【<table[^>]+?>】部分是匹配“<table class=”t1 t2″>”这种table的开头,包括属性的字符串,其中,使用了忽略优先量词(非贪婪),由于其属性不会太多,常规下不超过50个字符串,所以,没有使用固化分组,或者占有优先量词来减少回溯。
  2. 【</table>】(最后面的)是匹配字符串结束的。不用解释了吧。
  3. 【(?>((?!</table>).(?<!<table))+)】这个比较长,主要是匹配<table….到</table>中间的字符串,其中最外面一层【(?>)】是占有优先量词,用来防止不必要的回溯,防止中间超长的字符串造成崩溃。【(?!</table>)】是顺序零宽断言非操作,匹配位置,针对其后面的规则【.】,意思就是说,规则【.】后面不能是字符串“</table>”,同样正则【(?<!<table】是逆序零宽断言非操作,也匹配位置,针对其前面的规则【.】,意思就是说,规则【.】前面不能是字符串“<table…”,这样,两个零宽断言来确定一个字符串,如果是多个字符串,则加上匹配优先量词【+】,但是这个【+】的位置要注意了,不能直接放在【.】的后面,因为要保证每个【.】匹配的字符串,前后的规则都符合两个零宽断言,则需要放在外面,也就是上面所写的那样。

OK,解释完毕,你明白了没?如果没,那是我的错。请留言,批评,我承认错误。(当使用匹配的时候,为了更准确,建议开启不区分大小写模式,以及,多行匹配模式,即修饰符i和修饰符s,小写的s,不是大写的,大写的S是另外的含义<以后写>。)

见截图:

相对比较严谨,比较准确的正则表达式

测试代码:

$str='111<table class="t1 t2"><tr><td><table class="t1 t2">sssssssssssssssss</table></td></tr><tr>
<td><table class="t1 t2">ss
sssssssssssssss</table></td></tr></table>ssss';
preg_match_all('%<table[^>]+?>(?>((?!</table>).(?<!<table))+)</table>%si', $str, $result, PREG_PATTERN_ORDER);
print_r($result[0]);

我的答案可以解决问题吗?可以。准确吗?还行,不太准。为什么?如果table中间有嵌套,则无法正确匹配。如何修复?正则递归匹配。如果递归?

留给你研究吧。CFC4N小试正则表达式里已经介绍了一个关于递归匹配的例子,你可以参考一下。

后续:

老爷机挂了,我一夜没睡着,早上6点10分就醒了,起来之后,捣鼓两下,也没心情了,已经知道大体的症状。手头没工具,也没法测试,算了,索性洗漱去公司。走的早也好,地铁上没多少人,一路不拥挤,唯一的缺点就是没拿到“时代报”。不过到了公司楼下,有派发的,顺手拿了一份。到座位上,心思还在我心爱的老爷机上,也有重新买台新机器的想法,到DELL官方网站上搜了几下,发现价格奇贵,光主机,都4K-5K,看了一会,我就大小这个念头了,作为寄生在这大城市的P民,也别要求太高了。讲究用吧。哎,打算周末冒热抱出去找维修铺,各位,祝福我吧。

PS:下午,拿了早上没看的报纸去厕所,心想,这次终于不干等了,可以打发时间了。当我到厕所里的时候,我震惊了,我靠,马桶上起码5份报纸,而且,还都不一样。汗。

5 thoughts on “周末记事-还是我的老爷机

发表评论

电子邮件地址不会被公开。 必填项已用*标注