正则表达式在Perl中添加小数后的字符?

时间:2015-10-02 16:00:59

标签: regex perl

我有500个大小混乱的数据集(.csv)的列表,如下所示:

0.00, 0.53, 1.53, 0.00 0.52, 243.21 
... etc etc. 

我想:

0.00, 0.53, 1.53, 0.00, 0.52, 243.21 

在perl(或bash)中,我如何匹配小数点后的所有内容,如果有空格后跟另一个数字,那么我会插入一个逗号在第一个号码之后?

即。 0.00 0.52进入0.00, 0.52

我是perl和编程的初学者,所以我不太了解如何正确使用它。 我发现正则表达式[0-9]+(\.[0-9][0-9]?)?应该适用于两位小数,但是更多的小数呢?只是[0-9]+(\.[0-9]+?)?

我未成功的尝试:

for my $file (glob '*.csv') {
    open my $in, '<', $file;        
    my @lines;
    while (<$in>) {
        while(/^[0-9]+(\.[0-9]+)?$/g){
            print ",";      # Am I overwritting my lines here?  
        }
        $line =~ s/,,/,/g; # Get rid of any double commas that appear now
    }
    close $in;
    open my $out, '>', $file;
    print $out $_ for @lines;
    close $out;
}

我认为我没有正确匹配/打印 - 感谢任何帮助,包括更优雅的解决方案。

提前谢谢!

3 个答案:

答案 0 :(得分:2)

去懒惰:

#!/usr/bin/env perl 
use strict;
use warnings;

while ( <DATA> ) { 
    print join ( ", ", m/([\d\.]+)/g ); 
}

__DATA__
0.00, 0.53, 1.53, 0.00 0.52, 243.21 

输出:

0.00, 0.53, 1.53, 0.00, 0.52, 243.21

这适用于:

  • 重复将“数字和点”匹配到数组中
  • 然后用逗号分隔打印。 join未插入 尾随分隔符。

所以要拿你的代码:

#!/usr/bin/env perl 
use strict;
use warnings;

for my $file (glob '*.csv') {
    open my $in, '<', $file or die $!;
    open my $out, '>', "$file.new" or die $!; 

    while (<$in>) {
        print {$out} join ( ", ", m/([\d\.]+)/g ); 
    }
}

这是有效的,因为while循环的每次迭代都会自动将隐式变量$_设置为“当前行”。默认情况下,ms正则表达式(以及一堆其他perl函数)会在$_上运行。

所以你可以把它重写为:

while ( my $line = <$in> ) {
    my @stuff = $line =~ m/([\d\.]+)/g;
    print {$out} join ( ",", @stuff );
}

隐式变量对某些东西很好,但要警惕它们 - 只有在它们使代码更清晰时才使用它们。

要回答您的内联查询:

  

我在这里覆盖我的台词吗?

不 - print ","正在写STDOUT。这根本不会改变你的档案。 (但它实际上也没有做任何有用的事情)。

您必须使用s模式搜索/替换$_ - 当前行 - 然后push进入@lines

我认为你在这里误解了几个基本概念:

  • @lines$line无关。您实际上并没有对@lines执行任何操作,因此在打印时它将为空。
  • 您的whileprint循环 - 没有做任何事情。 m正则表达式 适用于$_,它由while循环隐式设置为“当前行”。但你实际上没有改变这个值。
  • $line =~ ...转换$line。但$line不存在,所以没有任何反应。

你真的应该在程序的开头添加use strict;use warnings,因为你会被警告这些事情。

答案 1 :(得分:0)

我不会说perl,但原则上说:

Search: (?<=\.\d\d)(?= \d)
Replace: ,

答案 2 :(得分:0)

如果你可以安装Tie :: File,你可以这样做:

use strict;
use warnings;
use Tie::File;

for my $file (glob '*.csv') {
    tie my @file, 'Tie::File', $file or die $!;
        s/(\d)(\s+\d)/$1,$2/g foreach (@file);
    untie @file;
}

请注意,这将修改原始文件。 Tie :: File将文件读入数组并允许您修改数据。