簡體   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