我是perl的新手,我正在试图找出并替换。我有一个大的csv文件(实际上是分号分隔)。文件中的某些数字(int和decimal)在数字后面有一个负号。我需要将负号移到数字前面。
E.g:改变
ABC;10.00-;XYZ
到
ABC;-10.00;XYZ
我不确定如何在perl中执行此操作。有人可以帮忙吗?
此致 阿南德
答案 0 :(得分:2)
除非我非常确定我的数据和正则表达式,否则我不会涉及带有正则表达式的大型csv文件。在我看来,使用CSV模块是最安全的方式。
此脚本将输入文件作为参数,并使用.new
扩展名编写更正的文件。
如果您发现输出文件发生了意外更改,可以尝试取消评论keep_meta_info
行。
use strict;
use warnings;
use autodie;
use Text::CSV;
my $out_ext = ".new";
my $csv = Text::CSV->new( {
sep_char => ";",
# keep_meta_info => 1,
binary => 1,
eol => $/,
} ) or die "" . Text::CSV->error_diag();
for my $arg (@ARGV) {
open my $input, '<', $arg;
open my $output, '>', $arg . $out_ext;
while (my $row = $csv->getline($input)) {
for (@$row) {
s/([0-9\.]+)\-$/-$1/;
}
$csv->print($output, $row);
}
}
答案 1 :(得分:1)
我假设您不必担心在分隔文件中引用或转义。我将从标准输入/输出读取,如果需要,则更改为适当的文件
while( my $line = <STDIN> )
{
chop( $line );
my @rec = split( ';', $line );
map( s/^(\d*\.?\d+)\-$/-$1/, @rec );
print join(';',@rec) . "\n";
}
如果您不必担心转义和引用,请使用Text::CSV_XS代替<STDIN>
,split
和join
oprerations
答案 2 :(得分:0)
通常,替换命令为s/old/new/flags
:
s/( # start a capture group
\d+ # first part of the number
(\.\d+)? # possibly a decimal dot and the fractional part
)- # end capture group, match the minus sign
/-$1/gx # move minus to the front
g
标志表示“全局”(替换所有出现),x
是“扩展易读性”(允许模式中的空格和注释)。您必须在数据上测试表达式以查看可能遗漏的角落情况,通常需要几次迭代才能获得正确的情况。样品:
$ echo "10.5-;10-;0-;a-" | perl -pe 's/(\d+(\.\d+)?)-/-$1/g'
-10.5;-10;-0;a-
另请参阅perldoc perlop
(搜索“替换”以跳转到右侧部分)。