[英]Find and replace words using sed command not working
我有一个制表符分隔的文本文件,第一列包含要找到的单词,第二列包含要替换找到的单词的单词。 一旦找到并替换了该单词,就不应再次更改它。
例如:
adam a +dam
a b
所以对于给定的文本文件:
adam played with a ball
我预计:
a +dam played with b ball
但是,我得到:
b +dbm plbyed with b bbll
我正在使用以下 sed 命令来查找和替换:
sed -e 's/^/s%/' -e 's/\t/%/' -e 's/$/%g/' tab_sep_file.txt | sed -f - original_file.txt >replaced.txt
我该如何解决这个问题
您的方法的基本问题是您不想将先前替换中的匹配文本替换为以后的替换 - 您不想将a +dam中的 a 更改为b 。 这使得sed
成为一个非常糟糕的选择 - 你可以创建一个匹配所有你想要替换的东西的正则表达式,但是选择使用哪个替换是一个问题。
一种使用 GNU awk
的方法:
gawk -F'\t' '
FNR == NR { subs[$1] = $2; next } # populate the array of substitutions
ENDFILE {
if (FILENAME == ARGV[1]) {
# Build a regular expression of things to substitute
subre = "\\<("
first=0
for (s in subs)
subre = sprintf("%s%s%s", subre, first++ ? "|" : "", s)
subre = sprintf("%s)\\>", subre)
}
}
{
# Do the substitution
nwords = patsplit($0, words, subre, between)
printf "%s", between[0]
for (n = 1; n <= nwords; n++)
printf "%s%s", subs[words[n]], between[n]
printf "\n"
}
' tab_sep_file.txt original_file.txt
哪个输出
a +dam played with b ball
首先,它读取 TSV 文件并构建要替换的单词数组和替换为 ( subs
) 的文本。 然后在读取该文件后,它会构建一个正则表达式来匹配所有可能找到的单词 - 在这种情况下是\<(a|adam)\>
。 \<
和\>
仅分别匹配单词的开头和结尾,因此球中的a将不匹配。
然后对于包含要处理的文本的第二个文件,它使用patsplit()
将每一行拆分为匹配部分( words
)和匹配之间的位( between
)的数组,并迭代数组的长度,打印输出每个匹配项的替换文本。 这样可以避免重新匹配已经被替换的文本。
还有一个使用相同方法的perl
版本:
perl -e '
my %subs;
open my $words, "<", shift or die $!;
while (<$words>) {
chomp;
my ($word, $rep) = split "\t" ,$_, 2;
$subs{$word} = $rep;
}
my $subre = "\\b(?:" . join("|", map { quotemeta } keys %subs) . ")\\b";
while (<<>>) {
print s/$subre/$subs{$&}/egr;
}
' tab_sep_file.txt original_file.txt
(这个会转义要替换的单词中的正则表达式元字符,使其更健壮)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.