linux - 对制表符分隔文件中的每一列执行不同的正则表达式

标签 linux perl bash unix

我发现自己在大约 8 年内第一次编写 PERL,但我在做一些本应容易的事情时遇到了困难。这是基本前提:

一个包含大约一百个字段的文件,其中 10 个字段的数据不正确(O 为 0)

A   B   C   D    E  F   ... 
br0wn   red   1278076   0range   "20 tr0ut"   123 ...
Green   0range   90876   Yell0w   "18 Salm0n"   456   ...

我正在尝试编写程序来拆分字段,然后允许我在字段 A 上运行正则表达式以将 0 替换为 O 但不将 0 替换为 C 列的 O 等等我还有一个额外的问题需要例如,可能为 E 列运行备用正则表达式。

我能够通过/t 拆分记录中的所有字段。我在格式化我的命令以遍历每个字段并根据它所在的字段运行特定的正则表达式时遇到问题。

如有任何帮助,我们将不胜感激,如果您解决了问题,我将通过 Paypal 向您支付 10 美元,用于购买您选择的饮料。

最佳答案

使用诸如 Text::CSV 之类的 csv 解析器并不复杂。像这样的东西可能就足够了:

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new({
        sep_char    => "\t",
        binary      => 1,
        eol         => $/,
});
while (my $row = $csv->getline(*DATA)) {
    tr/0/o/ for @{$row}[0, 1, 3];            # replace in cols A, B and D
    s/(?<!\d)0(?!\d)/o/g for @{$row}[4];     # replace in col E
    $csv->print(*STDOUT, $row);              # print the result
}


__DATA__
A   B   C   D   E   F
br0wn   red 1278076 0range  "20 tr0ut"  123
Green   0range  90876   Yell0w  "18 Salm0n" 456

输出:

A       B       C       D       E       F
brown   red     1278076 orange  "20 trout"      123
Green   orange  90876   Yellow  "18 Salmon"     456

请注意,我使用简单的正则表达式而不是音译(全局替换)来处理您的混合字符串(E 列),并且它根本不会替换数字旁边的零,这对于某些数字会失败,例如 20.00

更新:

如果您想根据列名称 而不是位置进行替换,事情会变得有点复杂。但是,Text::CSV 可以处理它。

use strict;
use warnings;
use Text::CSV;

my @pure_text   = qw(A B D);
my @mixed       = qw(E);

my $csv = Text::CSV->new({
        sep_char    => "\t",
        binary      => 1,
        eol     => $/,
});

my $cols = $csv->getline(*DATA);              # read column names
$csv->print(*STDOUT, $cols);
$csv->column_names($cols);                    # set column names

while (my $row = $csv->getline_hr(*DATA)) {   # hash ref instead of array ref
    tr/0/o/ for @{$row}{@pure_text};          # substitution on hash slice
    s/(?<!\d)0(?!\d)/o/g for @{$row}{@mixed};
    my @row = @{$row}{@$cols};                # make temp array for printing
    $csv->print(*STDOUT, \@row);
}


__DATA__
A   B   C   D   E   F
br0wn   red 1278076 0range  "20 tr0ut"  123
Green   0range  90876   Yell0w  "18 Salm0n" 456

此代码是用于演示的独立代码。要在文件上尝试代码,请将 *DATA 更改为 *STDIN 并按如下方式使用脚本:

perl script.pl < input.csv

关于linux - 对制表符分隔文件中的每一列执行不同的正则表达式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14698706/

相关文章:

python - 使用Python在SSH中使用 "su -l"执行命令

linux - 有没有办法使某个脚本的 SIGSTOP 无效?

c - statvfs() 和 statfs() 系统调用之间的区别?

perl - 如何添加时间并将其替换为 Perl 中的文件?

java - 需要在 linux shell 命令中转义的字符列表

linux - 如何在不使用 awk 的情况下获取 USB 驱动器的挂载点?

perl - 如何将 foreach 与哈希引用一起使用?

algorithm - 给定数字列表,在使用 +-*/获得特定结果时保持数字顺序

bash - 使用xargs ssh到多台主机,收到:Name or service not known

python - 用于执行 Python 程序的 Bash 脚本