在perl中将字符串解析为哈希结构

时间:2012-10-22 08:43:36

标签: perl parsing hash

我有以下字符串:

$str = "list
    XYZ

    status1    : YES
    value1     : 100
    status2      : NO
    value2     : 200
Thats all";       

我想使用一个函数将其转换为哈希值,该函数将此字符串作为输入并返回一个哈希,status1 key YES例如。

怎么做?
以及如何引用返回的哈希?

4 个答案:

答案 0 :(得分:12)

与往常一样,有多种方法可以做到这一点。这里有五个。

纯正则表达式(YEAH!)

我认为这是最酷的一个。正则表达式返回所有捕获的列表,这正是我们想要用以下内容初始化哈希的列表:

my %regex = $str =~ /(\S+)\s*:\s*(\S+)/g;

迭代

对于大多数程序员来说,这是最直接的方式,我认为:

my @lines       = split /\R/ => $str;
my %iterative   = ();
for (@lines) {
    next unless /(\S+)\s*:\s*(\S+)/;
    $iterative{$1} = $2;
}

这里无需解释。我首先将split字符串排成行,然后迭代它们,留下看起来不像foo : bar的行。完成。

列表处理

将所有内容都写成一个大表单表达感觉有点hackish,但也许有趣的是学习更多表达方式:

my %list =  map     { /(\S+)\s*:\s*(\S+)/ and $1 => $2 }
            grep    { /:/ }
            split   /\R/ => $str;

从右到左阅读:与上面的例子一样,我们首先将字符串拆分为行。 grep过滤:的行,在最终地图中,我使用键和值转换长度为2的列表中的匹配行字符串。

减少列表

List::Util reduce 函数的非平凡用例非常罕见。这是一个,基于上面的列表方法,返回哈希引用

my $reduced = reduce {
    $a = { $a =~ /(\S+)\s*:\s*(\S+)/ } unless ref $a;
    $a->{$1} = $2 if $b =~ /(\S+)\s*:\s*(\S+)/;
    return $a;
} grep { /:/ } split /\R/ => $str;

状态机

这是一个有趣的用于白色空间分离的正则表达式。它需要跟踪状态:

# preparations
my $state   = 'idle';
my $buffer  = undef;
my %state   = ();
my @words   = split /\s+/ => $str;

# loop over words
for my $word (@words) {

    # last word was a key
    if ($state eq 'idle' and $word eq ':') {
        $state = 'got_key';
    }

    # this is a value for the key in buffer
    elsif ($state eq 'got_key') {
        $state{$buffer} = $word;
        $state          = 'idle';
        $buffer         = undef;
    }

    # remember this word
    else {
        $buffer = $word;
    }
}

答案 1 :(得分:2)

只是为了好玩(请注意,我建议使用memowe' s)这里是(ab)使用YAML的那个:

#!/usr/bin/env perl

use strict;
use warnings;

use YAML;

my $str = "list
    XYZ

    status1    : YES
    value1     : 100
    status2      : NO
    value2     : 200
Thats all";

$str = join "\n", grep { /:/ } split "\n", $str;
my $hash = Load "$str\n";

答案 2 :(得分:1)

#!/usr/bin/perl
use warnings;

$\="\n";

sub convStr {
        my $str = $_[0];
        my %h1=();
        while ($str =~m/(\w+)\s+:\s+(\w+)/g) {
                $h1{$1} =$2;
        }
        return \%h1;
}

my $str = "list
    XYZ

    status1    : YES
    value1     : 100
    status2      : NO
    value2     : 200
Thats all";

my $href=convStr($str);

foreach (keys(%$href)) {
        print $_ , "=>", $href->{$_};
}

在运行时,我得到:

status2=>NO
value1=>100
status1=>YES
value2=>200

答案 3 :(得分:0)

  my %hhash;
  my @lines = split /\s+\n/, $str;
          foreach (@lines)
          {
            $_=~s/^\s+//g;
            if(/:/)
            {
            $key=(split(/:/))[0];
            $value=(split(/:/))[1];
            $hhash{$key}=$value;
            }
          }