【问题标题】:Using a .csv file as a data pool for the sed function使用 .csv 文件作为 sed 函数的数据池
【发布时间】:2014-10-09 08:38:04
【问题描述】:

我有大量文本,我想使用 sed 进行批量替换,使用 .csv 文件作为数据池供 sed 参考。例如,如果我想创建一个如下所示的 .csv 文件:

bird,snake
tree,bush
river,stream

然后我想使用 sed 在我的文本中搜索第 1 列字符串并替换为第 2 列值。这是最好使用调用 sed 的 bash 脚本来完成的事情,还是使用 Perl 脚本会更成功?

【问题讨论】:

  • 您是否使用了tour 并阅读了How to ask a good question 上的帮助?
  • 这是replace string in a file with value from another file的副本,你应该可以在其中找到答案
  • 我没有参加巡演,但我会在有能力的时候参加。
  • @martin 链接的问题不是重复的。它特指通过第二个 csv 文件中包含的信息翻译 csv 文件中的一个字段。此处翻译的文本并非孤立于特定领域,因此这些解决方案不适用。

标签: bash perl csv sed


【解决方案1】:

最好的方法是让一个sed 脚本将映射文件转换为第二个sed 脚本,然后将其应用于要转换的数据。既然你说bash,我会假设你有process substitution 可用。如果你不这样做,那么要么升级bash,要么改用临时文件。

sed -i .bak -f <(sed 's%^ *\([^ ,]\{1,\}\), *\([^ ]\{1,\}\) *$%s/\1/\2/g%' \
                      control-file) \
    datefile-1 datafile-2 ...

正则表达式相当复杂,因为问题中显示的控制数据有前导空格,可能还有尾随空格,并且有一个逗号空格作为字段分隔符。如果控制文件中的数据以更正统的方式格式化:

bird,snake
tree,bush
river,stream

代码可以更简单:

sed -i .bak -f <(sed 's%\([^,]*\),\(.*\)%s/\1/\2/g%' control-file) \
    datefile-1 datafile-2 ...

【讨论】:

  • 观察:问题的原始版本有一个看起来更复杂的 CSV 文件,其中包含多个前导空格、一个单词、一个逗号、一个空格,可能还有尾随空格。该问题后来被编辑(由 OP 以外的人)删除前导空格和逗号后的空格,从而改变了答案的复杂性。如图所示,使用sed 可以解决问题;它也可以使用 Perl 解决(因为 Perl 的预期用途之一是作为 sed-killer - 因此与 Perl 一起分发的 s2p 命令 - 但杀死并不是 100% 成功)。
【解决方案2】:

使用 Perl。将 CSV 文件读入哈希,从哈希键构建正则表达式,并使用哈希对文本进行全局替换。

看起来像这样

use strict;
use warnings;
use 5.010;
use autodie;

my $str = <<'__END_TEXT__';
The ripple-necked bird sang melodies by the curling river while
the hooded tiger glowered in the tree beneath her, just out of reach.
__END_TEXT__

open my $fh, '<', 'words.csv';
my %patterns = map {
   chomp;
   split /,/, $_, 2;
} <$fh>;

my $re = join '|', sort { length $b <=> length $a } keys %patterns;

$str =~ s/\b($re)\b/$patterns{$1}/g;

say $str;

输出

The ripple-necked snake sang melodies by the curling stream while
the hooded tiger glowered in the bush beneath her, just out of reach.

【讨论】:

  • 如果我想用单个字母执行此任务怎么办?例如,将字母 a 转换为“oo”,将字母 e 转换为“i”,这样蛇 -> snoki ?
  • 如果您正在寻找字符串(任何长度)单词中,那么您需要从正则表达式中删除 \b 锚点。它们匹配单词边界,因此可以防止模式匹配不到完整单词的任何内容。
猜你喜欢
  • 2013-05-12
  • 2011-04-04
  • 2012-08-28
  • 1970-01-01
  • 1970-01-01
  • 2016-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多