如何快速查找和替换列表中的许多项目而不更换BASH中以前替换的项目?

Vil*_*age 1 bash optimization perl replace sed

我想在一些文本上执行许多查找和替换操作.我有一个UTF-8 CSV文件,其中包含要查找的内容(在第一列中)以及用(在第二列中)替换它的内容,从最长到最短排列.

例如:

orange,fruit2
carrot,vegetable1
apple,fruit3
pear,fruit4
ink,item1
table,item2
Run Code Online (Sandbox Code Playgroud)

原始档案:

"I like to eat apples and carrots"
Run Code Online (Sandbox Code Playgroud)

结果输出文件:

"I like to eat fruit3s and vegetable1s."
Run Code Online (Sandbox Code Playgroud)

但是,我想确保如果已经替换了一部分文本,那么它就不会混淆已经替换的文本.换句话说,我不希望它看起来像这样(它与vegetable1中的"table"匹配):

"I like to eat fruit3s and vegeitem21s."
Run Code Online (Sandbox Code Playgroud)

目前,我使用的方法非常慢,因为我必须完成整个查找和替换两次:

(1)将CSV转换为三个文件,例如:

a.csv     b.csv   c.csv
orange    0001    fruit2
carrot    0002    vegetable1
apple     0003    fruit3
pear      0004    fruit4
ink       0005    item1
table     0006    item 2
Run Code Online (Sandbox Code Playgroud)

(2)然后,使用匹配列替换a.csvin中的所有项目,使用周围的单词以确保以后匹配数字时没有错误:file.txtb.csvZZZ

a=1
b=`wc -l < ./a.csv`
while [ $a -le $b ]
do
    for i in `sed -n "$a"p ./b.csv`; do
        for j in `sed -n "$a"p ./a.csv`; do
            sed -i "s/$i/ZZZ$j\ZZZ/g" ./file.txt
            echo "Instances of '"$i"' replaced with '"ZZZ$j\ZZZ"' ("$a"/"$b")."
            a=`expr $a + 1`
            done
    done
done
Run Code Online (Sandbox Code Playgroud)

(3)然后再次运行同一个脚本,但ZZZ0001ZZZfruit2from 替换c.csv.

运行第一次替换需要大约2个小时,但由于我必须运行此代码两次以避免编辑已经替换的项目,因此需要两倍的时间.是否有更有效的方法来运行查找和替换不会对已替换的文本执行替换?

Sla*_*zic 6

这是一个在"一个阶段"中进行替换的perl解决方案.

#!/usr/bin/perl
use strict;
my %map = (
       orange => "fruit2",
       carrot => "vegetable1",
       apple  => "fruit3",
       pear   => "fruit4",
       ink    => "item1",
       table  => "item2",
);
my $repl_rx = '(' . join("|", map { quotemeta } keys %map) . ')';
my $str = "I like to eat apples and carrots";
$str =~ s{$repl_rx}{$map{$1}}g;
print $str, "\n";
Run Code Online (Sandbox Code Playgroud)