【问题标题】:Regex to add character after decimal in Perl?正则表达式在Perl中添加小数点后的字符?
【发布时间】:2015-10-02 16:00:59
【问题描述】:

我有一个包含 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;
}

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

提前谢谢你!

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    去懒惰:

    #!/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,因为您会收到有关这些事情的警告。

    【讨论】:

      【解决方案2】:

      我不会说 perl,但原则上:

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

      【讨论】:

        【解决方案3】:

        如果你可以安装 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 将文件读入数组并允许您修改数据。

        【讨论】:

          猜你喜欢
          • 2015-01-02
          • 2012-01-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-16
          相关资源
          最近更新 更多