使用诸如此类的 csv 解析器Text::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
or )将失败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