sed与Perl正则加全局替换标志仍无法替换所有匹配项问题求助
问题原因分析
两个命令的共同核心问题
正则全局替换的逻辑是:每完成一次匹配替换后,下一次匹配会从本次匹配结束的位置开始扫描。你写的两个正则都要求匹配内容必须包含sym,第一次替换完成后,扫描游标已经越过了首个sym的位置,后续再也匹配不到.*sym的规则,自然最多只能替换一次。
sed命令的单独问题
GNU sed对非贪婪量词.*?的支持非常有限,你写的.*sym.*?lopy实际执行时依然按贪婪逻辑匹配,直接跳过了sym后的第一个独立lopy,匹配到了lopy1里的lopy片段,所以最终只把lopy1改成了lad1,完全不符合预期。
Perl命令的单独问题
你的正则第一次匹配成功替换了sym后的第一个独立lopy,但替换后扫描游标已经移动到这个替换完成的lad之后,后续扫描时已经找不到sym,所以lopy1里的lopy没有被替换。
正确实现方案
Perl方案(兼容性好、逻辑简单)
利用e修饰符执行嵌套替换,先定位到首个sym的位置,保留前面的内容不动,把后面的所有lopy批量替换:
# 替换为lad的写法,输出为 lopy,lopy1,sym,lad,lad1,sym echo "lopy,lopy1,sym,lopy,lopy1,sym" | perl -pe 's/^(.*?sym)(.*)$/$1 . ($2 =~ s/lopy/lad/gr)/e' # 如果需要得到你示例中的lady结果,把替换值改成lady即可: echo "lopy,lopy1,sym,lopy,lopy1,sym" | perl -pe 's/^(.*?sym)(.*)$/$1 . ($2 =~ s/lopy/lady/gr)/e'
GNU sed方案
通过拆分字符串的方式实现,先把首个sym后的内容拆分出来,替换完成后再拼接:
echo "lopy,lopy1,sym,lopy,lopy1,sym" | sed -r 's/(sym)/\1\n/;h;s/.*\n//;s/lopy/lad/g;G;s/(.*)\n(.*)\n.*/\2\1/'
内容的提问来源于stack exchange,提问作者user1134991
相关产品推荐
相关产品推荐

