【问题标题】:How do I split a string into an array by comma but ignore commas inside double quotes?如何通过逗号将字符串拆分为数组但忽略双引号内的逗号?
【发布时间】:2011-06-26 08:02:52
【问题描述】:

我有一条线:

$string = 'Paul,12,"soccer,baseball,hockey",white';

我尝试将其拆分为具有 4 个值的 @array

print $array[2];

足球,棒球,曲棍球

我该怎么做?救命!

【问题讨论】:

    标签: regex arrays perl csv


    【解决方案1】:

    只需使用Text::CSV。从the source 可以看出,正确解析 CSV 是相当复杂的:

    sub _make_regexp_split_column {
        my ($esc, $quot, $sep) = @_;
    
        if ( $quot eq '' ) {
            return qr/([^\Q$sep\E]*)\Q$sep\E/s;
        }
    
       qr/(
            \Q$quot\E
                [^\Q$quot$esc\E]*(?:\Q$esc\E[\Q$quot$esc\E0][^\Q$quot$esc\E]*)*
            \Q$quot\E
            | # or
            [^\Q$sep\E]*
           )
           \Q$sep\E
        /xs;
    }
    

    【讨论】:

    • 有一些方法可以在没有安装权限的情况下安装模块。见stackoverflow.com/questions/251705/…。此外,如果模块是纯 perl,您可以简单地将其放在与脚本相同的目录中,或者将其放在您可以访问的某个目录中并使用 use lib "directory" 结构,请参阅 perldoc.perl.org/lib.html .
    • 纯粹的 perl 实现在这里 search.cpan.org/perldoc?Text::CSV_PP 。您甚至可以单击“源”链接并将其复制/粘贴到文件中(注意命名)。这应该有效。
    • 我将如何使用 TEXT::CSV?
    • @seaworthy,添加了答案stackoverflow.com/questions/4982542/…
    【解决方案2】:
    use strict;
    use warning;
    #use Data::Dumper;
    
    my $string = qq/Paul,12,"soccer,baseball,hockey",white/;
    
    #split string into three parts
    my ($st1, $st2, $st3) = split(/,"|",/, $string);
    #output: st1:Paul,12 st2:soccer,baseball,hockey  st3:white  
    
    #split $st1 into two parts
    my ($st4, $st5) = split(/,/,$st1);
    
    #push records into array
    push (my @test,$st4, $st5,$st2, $st3 ) ;
    
    #print Dumper \@test;
    print "$test[2]\n";
    

    输出:

    soccer,baseball,hockey 
    
    #$VAR1 = [
    #          'Paul',
    #         '12',
    #          'soccer,baseball,hockey',
    #          'white'
    #        ];
    

    【讨论】:

    • 有趣吗?我需要 Data::Dumper 做什么?
    • Data::Dumper 仅用于将数组显示为人类可读的形式。
    • 其实Data::Dumper是用来以Perl可读的形式展示一个Perl结构的。
    【解决方案3】:

    $string = "Paul,12,\"soccer,baseball,hockey\",white";

    1 while($string =~ s#"(.?),(.?)"#\"$1aaa$2\"#g);

    @array = map {$_ =~ s/aaa/ /g; $_ =~ s/\"//g; $_} 拆分(/,/, $string);

    $" = "\n";

    打印“$array[2]”;

    【讨论】:

    • Eeeeeek。那是一辆经过大量重新发明的(可能是越野车,但谁会费心检查)自行车。换句话说,请不要在 Text::CSV(_XS) 完美地完成工作并且已经解决了所有那些可怕的边缘和角落案例和错误时手动编写 CSV 解析器。跨度>
    【解决方案4】:

    标准模块Text::ParseWords 也会这样做。

    my @array = parse_line(q{,}, 0, $string);
    

    【讨论】:

    • 有趣,我不知道这存在。
    • Text::ParseWords 尝试复制 Bourne shell 引用规则,这些规则与大多数 CSV 解析器/发射器使用的规则不同。特别是,单引号和双引号都很重要,它使用反斜杠作为转义字符。因此,虽然它适用于这个特定示例,但它是 CSV 解析的糟糕选择。
    • hivemind 推断这是一个关于 CSV 解析的问题。 OP 很可能正在使用 Bourne shell 引用规则,这是许多现存的 CSV 方言之一或他们自己制定的方案。谁能说?我只是想回答实际提出的问题。
    • 您至少应该提到它还忽略单引号内的逗号,因为这不是 OP 要求的,如果数据包含撇号,可能会令人大吃一惊。 (特别是因为 Text::ParseWords 会为带有不平衡单引号的行返回一个空列表。)
    • 我碰巧不时回到这个问题上,我想我可能会发表评论。当我需要轻量级 CSV 解析时,我有时会像上面一样使用 parse_line,但首先我会使用 $string =~ s|'|\'|g;,其效果比预期的要好得多!
    【解决方案5】:

    响应如何使用 Text::CSV(_PP)。这是一个快速的。

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    use Text::CSV_PP;
    my $parser = Text::CSV_PP->new();
    
    my $string = "Paul,12,\"soccer,baseball,hockey\",white";
    
    $parser->parse($string);
    my @fields = $parser->fields();
    
    print "$_\n" for @fields;
    

    通常会通过cpan 实用程序安装Text::CSVText::CSV_PP

    为了解决您无法安装模块的问题,我建议您使用“纯 Perl”实现,以便您可以“安装”它。假设您将 Text::CSV_PP 源的文本复制到名为 CSV_PP.pm 的文件中,则上述示例将起作用,该文件位于与您的脚本在同一目录中创建的名为 Text 的文件夹中。您也可以将它放在其他位置并使用前面讨论的use lib 'directory' 方法。请参阅 herehere 了解使用 CPAN 模块绕过安装限制的其他方法。

    【讨论】:

    【解决方案6】:

    使用这个正则表达式:m/("[^"]+"|[^,]+)(?:,\s*)?/g;

    上述正则表达式全局匹配任何以逗号或引号开头的单词,然后根据起始字符(逗号或引号)匹配剩余的单词。

    这是一个示例代码和相应的输出。

    my $string = "Word1, Word2, \"Commas, inbetween\", Word3, \"Word4Quoted\", \"Again, commas, inbetween\"";
    my @arglist = $string =~ m/("[^"]+"|[^,]+)(?:,\s*)?/g;
    map { print $_ , "\n"} @arglist;
    

    这是输出:

    Word1
    Word2
    "Commas, inbetween"
    Word3
    "Word4Quoted"
    "Again, commas, inbetween"
    

    【讨论】:

      【解决方案7】:

      试试这个

        @array=($string =~ /^([^,]*)[,]([^,]*)[,]["]([^"]*)["][,]([^']*)$/);
      

      该数组将包含您期望的输出。

      【讨论】:

        猜你喜欢
        • 2011-12-25
        • 1970-01-01
        • 2020-08-03
        • 2013-04-02
        • 2020-04-05
        • 2018-12-28
        相关资源
        最近更新 更多