【问题标题】:Perl regex, insert value between commasPerl正则表达式,在逗号之间插入值
【发布时间】:2014-12-14 03:55:27
【问题描述】:

我有一个 CSV 文件,但有些字段是空的。

样本数据

ItemA,5,4,3,2,1
ItemB,7,,,2,4
ItemC,,,,2,
ItemD,,3,,,

我想在文件上传递一个 perl 单行,它会在每个逗号之间插入一个字符串,比如 NULL,或者在最后一个逗号之后,如果它后面不存在值。

所以在正则表达式之后,数据应该是这样的:

ItemA,5,4,3,2,1
ItemB,7,NULL,NULL,2,4
ItemC,NULL,NULL,NULL,2,NULL
ItemD,NULL,3,NULL,NULL,NULL

我不知道如何创建这个正则表达式,不胜感激。谢谢。

【问题讨论】:

    标签: regex perl


    【解决方案1】:

    简单,使用积极的后向和前瞻断言,如下所示。

    $ perl -pe 's/(?<=,)(?=,|$)/NULL/g' file
    ItemA,5,4,3,2,1
    ItemB,7,NULL,NULL,2,4
    ItemC,NULL,NULL,NULL,2,NULL
    ItemD,NULL,3,NULL,NULL,NULL
    
    • (?&lt;=,) 只是照顾所有的逗号。也就是说,它断言匹配必须以逗号开头。

    • (?=,|$) 匹配后紧跟一个逗号或行尾锚。所以它匹配所有逗号之间存在的所有边界和最后一个逗号旁边的边界。

    • 将匹配的边界替换为NULL 字符串将为您提供所需的输出。

    【讨论】:

      【解决方案2】:

      这是一个带有正则表达式的解决方案:

      $ perl -pe 's/,(?=,)|,$/,NULL/g' file.csv
      
      ItemA,5,4,3,2,1
      ItemB,7,NULL,NULL,2,4
      ItemC,NULL,NULL,NULL,2,NULL
      ItemD,NULL,3,NULL,NULL,NULL
      

      即匹配逗号后紧跟逗号 (,(?=,)) 或行尾的逗号 (,$),并将匹配的逗号替换为 ,NULL


      编辑:正如 Casimir et Hippolyte 所指出的,s/,(?=,|$)/,NULL/g 更简单。

      (匹配一个逗号紧跟另一个逗号或行尾)。

      【讨论】:

      • 把你的交替放在前瞻中。
      【解决方案3】:

      我不会使用正则表达式。使用核心模块Text::ParseWords

      perl -MText::ParseWords -lne'
          @w = parse_line (",", 1, $_);
          print join ",", map { (length) ? $_ : "NULL" } @w
      ' file
      ItemA,5,4,3,2,1
      ItemB,7,NULL,NULL,2,4
      ItemC,NULL,NULL,NULL,2,NULL
      ItemD,NULL,3,NULL,NULL,NULL
      

      或者使用split 的可选第三个参数。

      perl -lne'
          @F = split ",", $_, -1; 
          print join ",", map { (length) ? $_ : "NULL" } @F
      ' file
      ItemA,5,4,3,2,1
      ItemB,7,NULL,NULL,2,4
      ItemC,NULL,NULL,NULL,2,NULL
      ItemD,NULL,3,NULL,NULL,NULL
      

      【讨论】:

      • OP 要求使用正则表达式 perl oneliner,你说你不会使用正则表达式,有什么理由不这样做吗?
      • @outlyer 这只是我的个人意见。使用正则表达式解析 csv 文件从来都不是一个好的选择。解决方案可能很短,但可能会在奇怪的用例中中断。
      • 同意,正则表达式通常不是 CSV 的好选择,尽管您使用 split 的替代解决方案在某些用例中也会失败。 Text::ParseWords 似乎更健壮。
      【解决方案4】:

      你可以用这个:

      #!/usr/bin/perl
      
      use strict;
      use warnings;
      
      my $fpath = "./data.txt";
      
      open(my $fh, '<', $fpath) or die "*** Cannot open $fpath:\n$!\n";
      
      while ( <$fh> ) {
          while(1) { last if ( $_ !~ s/,\s*,/,NULL,/g ) }
          $_ =~ s/,\s*$/,NULL/g;
          print $_ . "\n";
      }
      

      【讨论】:

      • 我测试过,但这不起作用,它取代了一些但不是所有的实例。为什么正则表达式中有 \s*?
      • 文件 ./data.txt 是您的 CSV 文件。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-02
      • 2023-01-02
      相关资源
      最近更新 更多