[英]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.