Regex & Sed/Perl:匹配前面没有另一个单词的单词

Regex & Sed/Perl:匹配前面没有另一个单词的单词

我想使用sedperl替换前面没有特定单词的所有出现的单词。

例如,我有一个包含电影情节的文本文件,我想用角色的名字替换所有出现的姓氏,但前提是他们的名字不是紧接在姓氏之前。

示例文本可能如下所示:

John Smith and Jane Johnson talk about Smith's car.

我希望它看起来像这样:

John Smith and Jane Johnson talk about John's car.

如果我这样做sed 's/Smith/John/' file,那么我就会:

John John and Jane Johnson talk about John's car.

姓氏之前的名字始终相同。我不必处理John SmithFrank Smith。我只需要一种之前Smith没有的匹配方法。John

答案1

对于任何正则表达式能够向后查找的语言来说,这都是很容易的。当然,Perl 是列表中的第一个:

perl -pe 's/(?<!John\W)Smith/John/g' <<< "John Smith and Jane Johnson talk about Smith's car."

弱点是“John”和“Smith”之间有多个非单词字符。不幸的是,像+for这样的量词\W会引发“可变长度后向查找未实现”错误。

答案2

编辑..关于你的评论..这是一个新脚本,它不关心(例如)威廉·史密斯。它暂时混淆了它保留的模式史密斯(不变)。

sed -r 's/\<(John) (Smith)\>/\1\x01x\2/g; 
        s/\<Smith\>/John/g;  s/\x01x/ /g'

如果您担心先生 先生 夫人...那么这有效。

sed -r 's/\<(John|((M(r|rs|s))\.?)) (Smith)\>/\1\x01x\5/g
        s/\<Smith\>/John/g; s/\x01x/ /g'

您可以满足威廉将他的名字添加到或者列表,例如。
sed -r 's/\<(William|John|...


这是原来的脚本

sed -r 's/(^|[[:punct:]] |\<[a-z]+ )(Smith\>)/\1John/'

答案3

 sed -r 's/([^John] )Smith/\1John/g;s/([^Jane] )Johnson/\1Jane/g'

() 将捕获姓氏之前的非名字,因此它们在替换中被反向引用。

编辑

@manatwork,吉尔斯

你说得对。怎么样

sed -r 's/(John Smith)/temp1/g;s/Smith/John/g;s/temp1/John Smith/g'

这似乎可以解决问题。

相关内容