Text :: CSV_XS解析的错误?

时间:2014-09-08 16:44:53

标签: perl module

尝试使用Text :: CSV_XS来解析一些日志。但是,以下代码不符合我的预期 - 根据分隔符" "将行拆分为多个部分。

有趣的是,如果我删除字符串$a中的双引号,那么它将进行拆分。

不知道这是一个错误还是我遗漏了什么。谢谢!

use Text::CSV_XS;

$a = 'id=firewall time="2010-05-09 16:07:21 UTC"';

$userDefinedSeparator = Text::CSV_XS->new({sep_char => " "});
print "$userDefinedSeparator\n";
$userDefinedSeparator->parse($a);
my $e;
foreach $e ($userDefinedSeparator->fields) {
    print $e, "\n";
}

修改

在上面的代码段中,我将=(在time之后)更改为空格,然后才能正常工作。开始想知道这是不是一个bug呢?

$a = 'id=firewall time "2010-05-09 16:07:21 UTC"';

2 个答案:

答案 0 :(得分:3)

如果您实际上没有尝试解析csv数据,可以使用Text::ParseWords来获取时间字段,这是Perl 5中的核心模块。使用此模块的好处是它可以很好地处理报价

use strict;
use warnings;
use Data::Dumper;
use Text::ParseWords;

my $str = 'id=firewall time="2010-05-09 16:07:21 UTC"';
my @fields = quotewords(' ', 0, $str);
print Dumper \@fields;
my %hash = map split(/=/, $_, 2), @fields;
print Dumper \%hash;

<强>输出:

$VAR1 = [
          'id=firewall',
          'time=2010-05-09 16:07:21 UTC'
        ];
$VAR1 = {
          'time' => '2010-05-09 16:07:21 UTC',
          'id' => 'firewall'
        };

我还介绍了如何通过将数据添加到哈希来使数据更易于访问。请注意,哈希不能包含重复的键,因此您需要为每个新的time键添加新的哈希值。

答案 1 :(得分:2)

您将引号字符和转义字符集都保留为双引号",然后将它们嵌入要分割的字段中,从而混淆了模块。

同时禁用quote_charescape_char

use strict;
use warnings;

use Text::CSV_XS;

my $string = 'id=firewall time="2010-05-09 16:07:21 UTC"';

my $space_sep = Text::CSV_XS->new({
   sep_char    => ' ',
   quote_char  => undef,
   escape_char => undef,
});

$space_sep->parse($string);

for my $field ($space_sep->fields) {
    print "$field\n";
}

<强>输出

id=firewall
time="2010-05-09
16:07:21
UTC"

但是 note 你已经完成了与print "$_\n" for split ' ', $string完全相同的事情,这是首选,因为它更有效,更简洁。

此外,您必须始终 use strictuse warnings;并且从不使用$a$b作为变量名,因为它们被sort使用,因为它们毫无意义且不具备描述性。


<强>更新

正如@ThisSuitIsBlackNot指出的那样,你的意图可能不是分裂空格而是提取一系列key=value对。如果是这样,那么此方法将值直接放入哈希值。

use strict;
use warnings;

my $string = 'id=firewall time="2010-05-09 16:07:21 UTC"';

my %data = $string =~ / ([^=\s]+) \s* = \s* ( "[^"]*" | [^"\s]+ ) /xg;

use Data::Dump;
dd \%data;

<强>输出

{ id => "firewall", time => "\"2010-05-09 16:07:21 UTC\"" }

<强>更新

此程序将提取两个name=value字符串并在不同的行上打印。

use strict;
use warnings;

my $string = 'id=firewall time="2010-05-09 16:07:21 UTC"';

my @fields = $string =~ / (?: "[^"]*" | \S )+ /xg;

print "$_\n" for @fields;

<强>输出

id=firewall
time="2010-05-09 16:07:21 UTC"