如何使用grep实现多行且惰性的正则匹配?含XML场景问题
关于grep多行惰性匹配及XML文本处理的解决方案
嗨,针对你提出的两个问题,我来逐一给出实用的解决思路:
1. 能否用grep实现多行且惰性的正则搜索?
完全可以!不过得依赖GNU grep(Linux系统大多默认自带)的参数组合,核心是利用Perl兼容正则(-P)来支持惰性匹配,再配合多行模式参数让grep能跨行匹配:
- 惰性匹配:Perl正则支持
.*?这种非贪婪(惰性)语法,这是扩展正则(-E)不具备的; - 多行匹配:可以用
-z参数让grep把整个输入文件当作一个连续的文本块(而非逐行处理),再结合Perl正则里的(?s)修饰符,让.能匹配换行符,实现真正的跨行匹配。
2. XML文本中匹配<i>something.*?}</i>的问题解决
你提到-Pzo和-Ezo都无法满足需求,问题根源在这里:
-Ezo的问题:扩展正则(-E)本身不支持惰性匹配(.*?是Perl正则专属语法),所以不管怎么搭配参数,都没法实现非贪婪匹配;-Pzo的问题:你可能没在正则里启用单行模式——Perl正则默认.不匹配换行符,哪怕用-z把文件读成一个块,也需要手动加(?s)修饰符让.能匹配任意字符(包括换行)。
具体解决方法:
方法一:修正-Pzo的正则写法
直接在正则开头加上(?s),命令如下:
grep -Pzo '(?s)<i>.*?}</i>' your_xml_file.txt
(?s):启用Perl正则的单行模式,让.匹配换行;-z:将整个文件作为单一文本块处理,避免换行截断匹配;-P:启用Perl兼容正则,支持.*?惰性匹配;-o:只输出匹配到的内容,而非整行。
方法二:用Perl命令替代(适配非GNU grep环境)
如果你的系统是macOS这类默认用BSD grep的环境,-P参数可能不可用,直接用Perl命令更靠谱:
perl -0777 -ne 'print "$_\n" while /(?s)<i>.*?}<\/i>/g' your_xml_file.txt
-0777:读取整个文件到内存;-ne:循环处理输入,执行指定的正则匹配;/g:全局匹配所有符合条件的内容,逐个输出。
方法三:用专业XML工具(更可靠的长期方案)
正则处理XML其实是“权宜之计”,如果XML结构复杂(比如嵌套标签、属性、不规则换行),正则很容易出错。推荐用专门的XML处理工具,比如xmlstarlet:
# 提取所有包含"}"的<i>标签内容 xmlstarlet sel -t -v '//i[contains(text(), "}")]' your_xml_file.txt
你可以根据实际XML结构调整XPath表达式,这样能更精准、可靠地提取内容。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

