正则表达式 一个奇怪问题

2019-10-21 22:30:21 +08:00
 faketemp

测试工具:Notepad++
测试文本: http://www.baidu.com,http://www.123.com,http://www.sina.com,MAIN
测试正则: http.+?MAIN

测试结果: http://www.baidu.com,http://www.123.com,http://www.sina.com,MAIN

问题是非贪婪模式下最短匹配,结果不应该是“http://www.sina.com,MAIN”吗

百思不得其解中……

2157 次点击
所在节点    问与答
22 条回复
faketemp
2019-10-21 22:47:37 +08:00
以前未遇到过这种奇怪问题 测试多个编辑器 结果都是一样 实在是费解
shiji
2019-10-21 22:58:24 +08:00
.+? 。*? 是 Lazy。
懒惰的意思是,尽量少的匹配(不贪婪)直到满足条件。

那么最前面的 http 是满足条件的,regex 里面的 http 也会相应的“划掉”,在到达终点 MAIN 之前,不管贪婪还是懒惰,中间的都得包含进去,没得选。

(中途因为 http 已经匹配上了,再次看到 http 的时候 regex 会忽略,反正已经匹配了。)

所以 Lazy 不能保证最短。。。
faketemp
2019-10-21 23:09:27 +08:00
@shiji 看各种教程都说?符号是“最短匹配” 如果 lazy 不能保证最短 请问像上面需求如何才能匹配出所要的“最短匹配”结果呢(假设网址部分是不定长的)
faketemp
2019-10-21 23:17:00 +08:00
@shiji 能够理解你的讲解 要查找出“最短匹配”结果 想到一种折中方案 就是先将文本逆序 正则匹配出结果后再逆序一次 😁这种方案好像很笨……
lxk11153
2019-10-21 23:31:45 +08:00
中间部分是.+?匹配中的。你可以试试断言来排除中间的 ht 河蟹 tp
htt 河蟹 ps://blog.csdn.ne 河蟹 t/u01204 河蟹 7933/article/details/383 河蟹 65541
shiji
2019-10-22 00:15:27 +08:00
@faketemp 逆序其实不笨,并且很有效率。。

设想这样一个字符串

http://www.du.com,MAIN,http://www.123.com,http://www.sina.com,MAIN,http://www.baidu.com,MAIN,http://www.123.com,MAIN

你期望的输出是什么?


如果不逆过来, 试试
( http:((?<!MAIN|http).)*MAIN)

然后跑代码找出最短的
pkookp8
2019-10-22 00:29:29 +08:00
因为正则都是从前向后的吧
第一个 http 符合要求就开始匹配,然后才是.+?main 的最短
lukaz
2019-10-22 00:30:52 +08:00
针对测试文本,假设网址部分不含逗号,那么可以这样: http[^,]+,MAIN
faketemp
2019-10-22 00:31:49 +08:00
受以上指导启发 只能这样了 使用

http((?!http).)+?MAIN
或者
http[^http]+?MAIN
faketemp
2019-10-22 00:33:19 +08:00
@pkookp8 嗯 我甚至专门去查过 有什么正则支持逆序查找选项🤪
lukaz
2019-10-22 00:44:16 +08:00
[^http]的意思不是想当然的[^( http)],不能这么用
geelaw
2019-10-22 04:17:26 +08:00
Lazy 模式并不是 skip 模式。
你的需求可以用一个 NFA 解决,基本思路是匹配 http,以及一坨不含 http 和 ,MAIN 的串,以及 ,MAIN。见 https://www.v2ex.com/t/602716
faketemp
2019-10-22 06:48:29 +08:00
@lukaz 谢谢提示 深入测试一下确实如你所说 这种用法是不准确的
所以目前来看 就只能使用零宽断言 http((?!http).)+?MAIN
或者逆序后 lazy 模式查找

@geelaw 理论能够理解 只是最终结果没看懂🤪
noqwerty
2019-10-22 07:36:16 +08:00
以前一直觉得自己写正则还可以,在 V2 看了几个帖子之后感觉自己真的菜
toma77
2019-10-22 09:59:39 +08:00
我最讨厌正则
ClericPy
2019-10-22 11:14:32 +08:00
昨天就看到这帖子, 然后...
测试工具:Notepad++
劝退了
faketemp
2019-10-22 11:21:07 +08:00
@ClericPy 技术无关 zz

师夷长技以制夷

用 sublimetext 或者 emeditor 等测试 问题一样重现 个人习惯
ClericPy
2019-10-22 11:23:01 +08:00
@faketemp 太敏感了...
本来以为是聊正则的, 结果... 这软件我没装, 不知道会是什么效果, 不来坑楼主
ClericPy
2019-10-22 11:36:16 +08:00
又看了下那些回帖, 已经有答案了, 这个条件改用零宽断言是对的 http(?:(?!http).)+?MAIN
被测试工具四个字给误导了, 以为是上来问 notepad++ 软件问题

提个小建议, 以后跨工具测试正则可以 https://regex101.com/ 省的一个个工具去安装了
faketemp
2019-10-22 11:45:49 +08:00
@ClericPy 感谢关注

目前收集到的几个正则 实测都可以准确查找
分别为
http(?:(?!http).)+?MAIN
http:((?<!MAIN|http).)+?MAIN
http((?!http).)+?MAIN

记录一下给需要的 V 友学习哈

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/611557

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX