使用映射文件替换文件中的多个字符串

Posted

技术标签:

【中文标题】使用映射文件替换文件中的多个字符串【英文标题】:Replace multiple strings in file using a mapping file 【发布时间】:2014-06-07 21:00:32 【问题描述】:

如何使用映射文件(+ 50K 行)替换一个大文件(+ 500K 行)中的多个字符串?映射文件的结构如下:

A1  B1
A2  B2
A3  B3
..  ..

大文件的结构是这样的:

A1  A2
A1  A3
A1  A8
A2  A1
A2  A3
A3  A10
A3  A13

并且大文件中的每个字符串都必须使用映射文件进行替换。

想要的结果:

B1  B2
B1  B3
B1  B8
B2  B1
B2  B3
B3  B10
B3  B13

我尝试在映射文件的每一行上都使用 awk,但这需要很长时间……这是 awk 命令。所以我为映射文件的每一行编写了一个循环启动一个 awk 命令,我将结果保存在一个临时文件中,并将这个结果用于映射文件的下一行的新 awk(我知道效率不是很高..)

cat inputBigFile.txt | awk ' gsub( "A1","B1" );1' > out.txt

提前致谢

【问题讨论】:

究竟是什么awk 命令你试过太慢了? 搜索答案解释如何使用NR==FNR的众多近似重复项之一。 无论如何,您不应该将cat 数据发送到可以自行读取数据的程序中,例如awkawk ' gsub( "A1","B1" );1' inputBigFile.txt > out.txt。要查看程序使用了多长时间,请以 time eks: time awk 'code file > out` 开始它。 【参考方案1】:
$ awk 'NR==FNRmap[$1]=$2;next if($1 in map)$1=map[$1]; if($2 in map)$2=map[$2]1' mappings file
B1
B1
B1 A8
B2
B2
B3 A10
B3 A13

我假设专门检查和替换两列比循环 NF 和/或使用 gsub 更快。

编辑:重要的是:

$ wc -l file
8388608 file

.

$ time awk 'NR==FNRmap[$1]=$2;next if($1 in map)$1=map[$1]; if ($2 in map)$2=map[$2]1' mappings file >/dev/null
real    0m6.941s
user    0m6.904s
sys     0m0.016s

.

$ time awk 'NR==FNRmap[$1]=$2;next for(i=1;i<=NF;i++)$i=($i in map)?map[$i]:$i1' mappings file >/dev/null
real    0m10.311s
user    0m10.249s
sys     0m0.036s

.

$ awk --version | head -n 1
GNU Awk 3.1.8

【讨论】:

谢谢,太好了。但是您在 awk 命令中忘记了 $(在 $2=map[2] 中): awk 'NR==FNRmap[$1]=$2;next if($1 in map)$1=map[$1]; if($2 in map)$2=map[$2]1' 映射文件 一件事:如何强制以制表符分隔输出? @NicoBxl 使用awk -v OFS='\t' [...] 设置输出分隔符。但是,这只会影响至少其中一列已更改的行。要强制,您可以在if 之后添加显式print $1, $2(并删除尾随1),例如[...]; if($2 in map)$2=map[$2]; print $1, $2.

以上是关于使用映射文件替换文件中的多个字符串的主要内容,如果未能解决你的问题,请参考以下文章

从 Apache Beam 中的多个文件夹读取文件并将输出映射到文件名

Unicode 字符如何映射到字体中的字形?

用另一个文件中的值替换一个文件不能正常工作

映射多个 csv 文件中的字段并组合行

Struts:action配置文件之通配符映射

如何在hibernate.cfg.xml中的主配置文件中配置多个映射文件