sed分组匹配中*量词非贪婪问题与多字符串替换方案咨询
为什么
sed中(a|b)*没生效,而+可以? 首先得澄清一个误区:这不是贪婪与否的问题,而是*量词的特性导致的。
问题根源:*允许匹配0次
*量词的规则是匹配0次或多次目标内容,而sed的默认替换行为是只处理第一个找到的匹配项。
当你执行:
echo xab | sed -E 's/(a|b)*//'
sed会从字符串的起始位置开始查找匹配:
- 第一个字符是
x,不属于a或b,所以(a|b)*在这里只能匹配0个字符(空串); sed把这个空串替换成空,相当于没做任何修改,所以输出还是xab。
而+量词的规则是匹配1次或多次目标内容,它不能匹配0次。所以执行:
echo xab | sed -E 's/(a|b)+//'
时,sed会跳过开头的x,找到后面连续的ab(符合1次以上的匹配规则),将其替换为空,最终得到预期的x。
最佳解决方法
针对你替换任意数量目标字符串(比如更长的foo/bar这类,字符类无法满足)的需求,推荐两种方案:
用
+替代*(优先推荐)
既然你需要替换的是「存在的目标内容」,+能确保匹配至少1次目标序列,避免匹配0次空串的情况。比如:# 替换单个连续的目标序列 echo xq-as | sed -E 's/(foo|bar|xq)(-as|-gh|-ts)+//' # 如果要替换所有出现的目标序列,加`g`选项 echo xq-asxq-gh | sed -E 's/(foo|bar|xq)(-as|-gh|-ts)+//g'强制匹配非空的目标序列(兼容需用
*的场景)
如果你因为某些原因必须用*,可以通过添加断言确保匹配的是非空内容。比如结合\K(保留前面的内容,替换后面的):echo xab | sed -E 's/x\K(a|b)*//'这里
x\K表示匹配到x后,保留x,只替换后面的(a|b)*内容,这样就不会触发0次匹配的问题。不过这种方法需要你的sed支持\K(GNU sed 支持,BSD sed 可能不支持)。
额外提示
如果你的需求是删除所有目标字符/字符串的出现(不管位置),记得加上g全局替换选项,否则sed只会处理第一个匹配项。
内容的提问来源于stack exchange,提问作者Dan Kegel
相关产品推荐
相关产品推荐

