【问题标题】:Perl regex store matches in arrayPerl 正则表达式将匹配项存储在数组中
【发布时间】:2014-05-29 05:50:54
【问题描述】:

我有一个文件,每一行都有如下字符串

"229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1 下一行可能看起来像 84545,X,2

我正在尝试在 Perl 中解析此文本。注意:如果一行中有几个引号,则字符串中存在引号,但如果只有项目,则不存在 我想将每个项目解析成一个数组。我尝试了以下正则表达式

@fields = ($_ =~  /(\d+\_\d+),*/g);

但它缺少最后一个2714。我如何捕捉这种边缘情况?任何帮助表示赞赏。提前致谢

【问题讨论】:

  • 您的 2714 中没有“_”,因此请更改您的正则表达式。
  • 没有'_'正是我的问题。我尝试了 kirilloid 的建议,但它不起作用。

标签: regex perl


【解决方案1】:

您似乎有一个 CSV 文件,因此请使用实际的 CSV 解析器,例如 Text::CSV

解析列后,您可以将第一个字段分隔到数组中:

use strict;
use warnings;

use Text::CSV;

my $csv = Text::CSV->new ( { binary => 1 } )  # should set binary attribute.
    or die "Cannot use CSV: ".Text::CSV->error_diag ();

my $line = qq{"229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1 the next line could look like 84545,X,2};

if ($csv->parse($line)) {
    my @columns = $csv->fields();
    my @nums = split ',', $columns[0];

    print "@nums\n";
}

输出:

229269_2 190594_2 94552_2 266076_2 269628_2 165328_2 99319_2 263339_2 263300_2 99315_2 271509_2 2714

为什么不用正则表达式?

是的,当然,几乎任何事情都可以使用正则表达式。但是你需要明白的是,这会让你的代码变得极其脆弱,难以维护。

即使你想使用正则表达式,你也应该分两步完成。首先分离 CSV 的初始列,然后处理您担心的特定列。

因为您只处理第一列,您可以使用如下代码:

use strict;
use warnings;

my $line = qq{"229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1 the next line could look like 84545,X,2};

if ($line =~ /^"(.*?)"|^([^,]*)/) {
    my $column0 = $1 // $2;
    my @nums = split ',', $column0;

    print "@nums\n";
}

上面的代码恰好和前面的代码完成了同样的事情。然而,它有一个很大的缺陷,对于维护程序员来说,发生了什么并不那么明显。

每当新的编码人员,甚至是 6 个月后的您自己查看第一组代码时,您的数据采用的格式非常明显。您正在使用 CSV 文件,并且第一列是分隔的列表用逗号。第二个代码也可以,但新的维护者必须实际阅读正则表达式并弄清楚发生了什么,以了解数据的格式以及代码是否实际正确执行。

不管怎样,随心所欲,但我强烈建议您使用实际的 CSV Parser 来解析 csv 文件。

【讨论】:

  • 这行得通,但我试图避免使用 Text::CSV。有一个单行正则表达式吗?问题下的 cmets 正试图解决这个问题,但我没有任何运气。
  • 我提供了第二个选项,但我仍然建议您使用第一组代码。
【解决方案2】:

如果你想要的只是最后两个字段...

   my $string = qq("229269_2,190594_2,94552_2,266076_2,269628_2,165328_2,99319_2,263339_2,263300_2,99315_2,271509_2,2714",A,1);
   $string =~ s/"//g;            # delete the quotes
   my @f = split (/,/, $string); # split on the comma
   pop @f; pop @f;               # jettison the last two columns

   # @f contains what you're looking for

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-29
    • 2014-07-20
    • 2017-10-16
    相关资源
    最近更新 更多