我知道如何使用sed
语法[^xxxx]
来排除字符,但如何排除单词?例如我的变量:
var="
Now is the time
for all good men
to come
to the aid
of the party"
现在:
echo $var | sed ...
...我想最终得到:
REPLACED time
for all good men
to come
REPLACED aid
REPLACED party
...这应该很简单,但我不知道该怎么做。
echo $var | sed -r 's/^[^the]*the/REPLACED/'
... 有点接近,但它们t
h
e
被匹配为单个字符,而不是单词the
。
如果有解决方案,我可以替换所有内容,直到多次出现的第一个,甚至直到一个特定的出现,那就更好了。
答案1
您可以按如下方式实现:假设最多有一个实例the
假设线路上:
sed -E 's/.*\Wthe(\W.*)/REPLACED\1/'
the
这将用您的替换文本替换直到最后一次出现的所有内容(请记住,正则表达式是贪婪的) 。
- 它通过将最后一次出现后的所有内容存储在捕获组中
the
,并用非单词字符括起来(以防止部分单词匹配,例如theoretical
),包括以 , 结尾的非单词字符来实现此目的。the
( ... )
- 然后,它将用替换文本替换该行,后跟捕获组的内容(之所以称为 ,是
\1
因为它是搜索模式中的第一个此类组)。这种稍微复杂的方法是必要的,以便终止 的字符the
也被转移到替换文本。
如果您想更换所有内容第一的发生时,您可能不得不求助于awk
:
awk '(i=match($0,/\Wthe\W/)){print "REPLACED" substr($0,i+4);next} 1'
这将检查由非单词字符包围的字符串 是否the
出现在该行上,并将位置存储在变量 中i
。
- 如果
i
非零,它将打印替换文本和当前输入行开始的子字符串后的出现the
,但否则跳过执行到下一行。 - 如果
i
为零,它只是按原样打印当前行。
答案2
s/.*the/REPLACED/
替换最右边出现的所有内容,the
因为这.*
是贪婪的并且想要尽可能多地匹配。
.*
是 0 个或多个 ( *
) 个字符 ( .
)越多越好并且会很高兴地吞噬所有the
不包括最后一个需要与正则表达式的以下部分匹配的出现the
。
大约 30 年前, 5 引入了:perl
的变体,它也匹配 0 个或多个前面的内容,但是*
*?
尽可能少:
printf '%s\n' "$var" | perl -pe 's/.*?the/REPLACED/'
很少sed
有人增加了对这些新perl
运营商的支持。我只知道两种实现(ssed
with-R
和 ast-open 的 with -E
// -A
/ -X
)-P
。在其他sed
s 中,?
匹配文字?
或与-E
/匹配-r
,*?
要么是错误,要么与*
理解为*
运算符(0 或更多)与?
(0 或 1)组合相同。
对于sed
不支持的实现*?
,当要替换的内容是单个字符(如 )时x
,您可以使用s/[^x]*x/REPLACE/
除( )*
之外的 0 个或多个 ( ) 字符,尽可能多,并且因为我们排除,所以它将存储在第一个字符之前发生。x
[^x]
x
x
您不能将其用于超过 1 个字符的字符串,因为您不能尽可能多地表示 0 个或多个字符只要不包括“the”。所以你需要一种不同的方法。
s/the/REPLACEMENT/
替换第一次出现的,因此标准中替换字符串第一次出现之前的所有内容的the
常用方法是将其替换为换行符(否则保证该字符不会出现在模式空间中),然后sed
替换该换行符之前的所有内容:
sed 's/the/\
/;s/.*\n//'
答案3
如果您需要将所有内容替换为第一个,the
您可能需要非贪婪量词,而基本正则表达式和扩展正则表达式都无法识别这些量词。
在这种情况下,如果sed
对您来说不是强制性的,您可以使用perl
:
perl -pe 's/.*?\Wthe/REPLACED/'
如果您需要替换最多n
出现的次数(替换n
为您的出现次数):
perl -pe 's/(.*?\Wthe){1,n}/REPLACED/'