繁体   English   中英

如何使用Perl中的关键字将字符串解析为哈希?

[英]How can I parse a string into a hash using keywords in Perl?

我有一个字符串,不同的预定义关键字引入不同的数据 有没有办法通过巧妙地使用正则表达式或其他东西来做到这一点? 这是一个例子:

关键字可以是"first name: ""last name: " 现在我要解析:

"character first name: Han last name: Solo"

{ "first name: " => "Han ", "last name: " => "Solo" }

当然,输入字符串中关键字的顺序不固定。 这应该也适用于:

"character last name: Solo first name: Han"

我理解有空格等问题。 我会在这里忽略它们。

我知道如何解决这个问题循环不同的关键字,但我发现这不是很漂亮。

拆分几乎符合要求。 它唯一的问题是它返回一个数组而不是一个哈希,所以我不知道哪个是名字或姓。

我的例子有点误导。 这是另一个:

my @keywords = ("marker 1", "marker 2", "marker 3");
my $rawString = "beginning marker 1 one un marker 2 two deux marker 3 three trois and the rest";
my %result;
# <grind result>
print Dumper(\%result);

将打印:

$VAR1 = {
      'marker 2' => ' two deux ',
      'marker 3' => ' three trois and the rest',
      'marker 1' => ' one un '
    };

这是一个使用split (带分隔符保留模式)的解决方案,可以使用其他键进行扩展:

use warnings;
use strict;

my $str = "character first name: Han last name: Solo";

my @keys = ('first name:', 'last name:');

my $regex = join '|' => @keys;

my ($prefix, %hash) = split /($regex)\s*/ => $str;

print "$_ $hash{$_}\n" for keys %hash;

打印:

last name: Solo
first name: Han 

要处理包含正则表达式元字符的键,请将my $regex = ...行替换为:

 my $regex = join '|' => map {quotemeta} @keys;

以下循环遍历字符串一次以查找匹配(在规范化字符串之后)。 避免循环的唯一方法是每个关键字只能在文本中出现一次。 如果是这样的话,你可以写

my %matches = $string =~ /($re):\s+(\S+)/g;

并完成它。

下面的脚本处理可能的多次出现。

#!/usr/bin/perl

use strict; use warnings;

use File::Slurp;
use Regex::PreSuf;

my $re = presuf( 'first name', 'last name' );

my $string = read_file \*DATA;
$string =~ s/\n+/ /g;

my %matches;

while ( $string =~ /($re):\s+(\S+)/g ) {
    push @{ $matches{ $1 } }, $2;
}

use Data::Dumper;
print Dumper \%matches;

__DATA__
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore character first name: Han last
name: Solo et dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud character last name: Solo first name: Han exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse cillum
character last name: Solo first name: Han dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in
culpa qui officia deserunt mollit anim id est laborum
use strict;
use warnings;
use Data::Dump 'dump';   # dump allows you to see what %character 'looks' like

my %character;
my $nameTag = qr{(?:first|last) name:\s*};

# Use an array slice to populate the hash in one go
@character{ ($1, $3) } = ($2, $4) if $string =~ /($nameTag)(.+)($nameTag)(.+)/;

dump %character; # returns ("last name: ", "Solo", "first name: ", "Han ")

这有效。

use 5.010;
use Regexp::Grammars;
my $parser = qr{
        (?:
            <[Name]>{2}
        )
        <rule: Name>
            ((?:fir|la)st name: \w+)
}x;

while (<DATA>) {
    /$parser/;
    use Data::Dumper; say Dumper $/{Name};
}

__DATA__
character first name: Han last name: Solo
character last name: Solo first name: Han

输出:

$VAR1 = [
          ' first name: Han',
          ' last name: Solo'
        ];

$VAR1 = [
          ' last name: Solo',
          ' first name: Han'
        ];

这可能是IF:

1)您可以识别可以选择标记的一小组正则表达式2)可以写入用于提取值的正则表达式,以便它仅选取值并忽略值之后的无关数据(如果有的话)和下一个标签的开头。

以下是使用非常简单的输入字符串进行操作的示例。 这是一个调试会话:

  DB<14> $a = "a 13 b 55 c 45";
  DB<15> %$b = $a =~ /([abc])\s+(\d+)/g;
  DB<16> x $b
0  HASH(0x1080b5f0)
   'a' => 13
   'b' => 55
   'c' => 45

使用Text :: ParseWords。 它可能并不能完成您想要的所有功能,但是您可以更好地构建它,而不是尝试从头开始解决整个问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM