我发现自己在大约 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.0
或 0
。
更新:
如果您想根据列名称 而不是位置进行替换,事情会变得有点复杂。但是,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/