使用“sed”替换最多一个单词(而不是一个字符)的任何内容

使用“sed”替换最多一个单词(而不是一个字符)的任何内容

我知道如何使用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运营商的支持。我只知道两种实现(ssedwith-R和 ast-open 的 with -E// -A/ -X-P。在其他seds 中,?匹配文字?或与-E/匹配-r*?要么是错误,要么与*理解为*运算符(0 或更多)与?(0 或 1)组合相同。

对于sed不支持的实现*?,当要替换的内容是单个字符(如 )时x,您可以使用s/[^x]*x/REPLACE/除( )*之外的 0 个或多个 ( ) 字符,尽可能多,并且因为我们排除,所以它将存储在第一个字符之前发生。x[^x]xx

您不能将其用于超过 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/'

相关内容