如何从此键值对中提取值?

时间:2015-02-25 09:22:17

标签: regex perl

我有一个由','分隔的键值对,如下所示。我只需要提取值,无论它是否存在。

Category=, userAgent=Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko, referringURL=https://www.localhost.com/account/pay?link=credit_card, criteria=InFormCriteria(cc='MZ',tend=123,cd='parts')

我使用了以下代码,

while(<FH>){
    while($_=~m/([^=]+)=([^\s]+,?)/g){
        print $1." ";
    }
    print "\n";
}

我得到以下输出:

, Mozilla/5.0 https://www.localhost.com/account/pay?link=credit_card, InFormCriteria(cc='MZ',tend=123,cd='parts')

但是,我需要得到:

""@@Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko@@https://www.localhost.com/account/pay?link=credit_card@@InFormCriteria(cc='MZ',tend=123,cd='parts')

我做错了什么?

2 个答案:

答案 0 :(得分:1)

它比听起来更烦人,因为你的字符串使用不一致的分隔符。因此,很难用RE解析,并且总是不可靠。

存在这样做的模块 - 正如Wintermute所提到的,HTTP::BrowserDetect是为解析这种特殊类型的字符串而构建的。

如果你真的开始这么做的话 - 简单的&#39;由于在括号中嵌套了元素,split_on_delimiter方法无法工作。所以我建议 - 用正则表达式挑选密钥(因为它们总是一个字,然后是=)。

然后,创建一堆&#39; sub&#39;正则表达式,解析它。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $string =
    q{Category=, userAgent=Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko, referringURL=https://www.localhost.com/account/pay?link=credit_card, criteria=InFormCriteria(cc='MZ',tend=123,cd='parts')};

my @keys = ( $string =~ m/(?:^|\s)(\w+)=/g );
my %parsed_thing;

for my $index ( 0 .. $#keys ) {
    my $regex =
          $keys[$index]
        . '=(.*?)[, ]*'
        . ( defined $keys[ $index + 1 ] ? $keys[ $index + 1 ] : '$' );
    print "Using a RE of: ", $regex, "\n";

    my ($value) = ( $string =~ m/$regex/ );
    print "\tGot: $keys[$index] => $value\n";
    $parsed_thing{ $keys[$index] } = $value;
}

print join( '@@', values %parsed_thing ),"\n";
#or
print join( '@@', @parsed_thing{@keys} ),"\n";

答案 1 :(得分:1)

您的实际分隔符看起来更像,(逗号后跟空格)。如果key = value对的值不包含相同的分隔符,则可以使用gawk:

gawk '{sub(/^\w+=/, ""); gsub( /, \w+=/, "@@"); print}'

删除第一个字段中的key = part,然后将其他字段转换为@@。您的示例数据输出对我来说是这样的:

@@Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko@@https://www.localhost.com/account/pay?link=credit_card@@InFormCriteria(cc='MZ'@@123@@'parts')

如果您确实需要将空值表示为"",则可以在脚本中使用常规gawk / awk:

#!/usr/bin/awk -f

BEGIN {FS=", "; OFS="@@"}

{
    for(i=1; i<=NF; i++) {
        val = substr( $i, index( $i, "=" )+1 )
        if( val=="" ) val="\"\""
        printf "%s%s", val, (i<NF?OFS:"\n")
    }
}

或者,你也可以将这些字段分成或者gsub到""。该脚本为我输出以下内容:

""@@Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko@@https://www.localhost.com/account/pay?link=credit_card@@InFormCriteria(cc='MZ',tend=123,cd='parts')

这些解决方案都假设每个字段都是key = value,并且没有值包含,(逗号后跟空格)。如果后者不成立,那么您可能希望将日志记录定界符(如果可以)更改为更明确的内容。或者,如果您可以确定,在某个值中的不同情况(例如在平衡数据之间),则可以在解析主键=值对之前更改这些情况。