为什么当我们使用否定表达式时,sed[^ ]
会将锚字符视为\b
真实\B
字符?例如,人们可能期望以下表达式产生相同的结果,但事实并非如此:
$ echo 'apple pear melon banana cherry papaya' | sed 's/[^\b]a[^\b]/u/g'
apple pu melon baua cherry uaya
$ echo 'apple pear melon banana cherry papaya' | sed 's/\Ba\B/u/g'
apple peur melon bununa cherry pupuya
如果没有\B
,我们怎么能否定呢\b
?
答案1
两者都不是\b
或\B
是字符。两者都是匹配的零宽度模式之间人物。
该\b
模式在单词边界处匹配,即在作为“单词字符”的字符和不是“单词字符”的字符之间匹配。
该\B
模式在非单词边界处匹配,即在两个字符之间匹配,这两个字符要么是“单词字符”,要么不是。
模式[^\b]
匹配一个字符。这就是为什么pear
转化为pu
,你替换ear
(thea
和周围的字符)。
对于 GNU sed
,匹配不是 an或 a 的[^\b]
字符。\
b
没有办法使用字符类来代替\B
我所知道的字符类的使用。
GNU 支持\b
和模式。 GNU和 BSD都有and用于在单词的开头和结尾显式匹配,并且 BSD还支持 POSIX 模式and (但 GNU不支持)。 POSIX 模式无法被否定(不起作用)。\B
sed
sed
sed
\<
\>
sed
[[:<:]]
[[:>:]]
sed
[^[:>:]]
为了得到一个相似的效果而不使用\B
,你可以使用类似的东西
$ echo 'apple pear melon banana cherry papaya' | sed 's/\([[:alnum:]]\)a\([[:alnum:]]\)/\1u\2/g'
apple peur melon bunana cherry pupaya
也就是说,匹配 两侧的字母数字字符a
,然后在替换中包含这两个侧翼字符。请注意,由于替换仅发生在非重叠匹配项中,因此这不会正确替换包含多个连续'(或每隔一个位置都有 ')a
的字符串中的 ' 。看看如何不会因为这个而出现。a
a
banana
bununa
为了解决这个问题,您可以在sed
程序中引入一个循环:
sed -e :top -e 's/\([[:alnum:]]\)a\([[:alnum:]]\)/\1u\2/g' -e ttop
这会根据需要对输入行执行多次替换,直到处理完所有重叠的模式匹配。