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)然后再次运行同一个脚本,但ZZZ0001ZZZ用fruit2from 替换c.csv.
运行第一次替换需要大约2个小时,但由于我必须运行此代码两次以避免编辑已经替换的项目,因此需要两倍的时间.是否有更有效的方法来运行查找和替换不会对已替换的文本执行替换?
这是一个在"一个阶段"中进行替换的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)