我想使用sed
或perl
替换前面没有特定单词的所有出现的单词。
例如,我有一个包含电影情节的文本文件,我想用角色的名字替换所有出现的姓氏,但前提是他们的名字不是紧接在姓氏之前。
示例文本可能如下所示:
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 Smith
和Frank 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'
这似乎可以解决问题。