2010-05-25 27 views
2

我有一個字符串,其中不同的預定義關鍵字引入了不同的數據。有沒有辦法做到這一點,巧妙地使用正則表達式,或者什麼?這裏是一個例子:如何在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 ' 
    }; 
+1

可以有多個名字和姓氏,比如'Jean Marc'或'Syu Kyi'嗎? – Zaid 2010-05-25 14:08:54

+0

是的。該示例使用名稱,但它確實是一個字符串問題:匹配標記字符串並返回之間的所有字符作爲前一個標記的值。 – 2010-05-25 14:20:31

回答

7

這裏是使用溶液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; 
+0

謝謝。這是完美的。我不知道分裂可能會返回一個散列,就像你在這裏展示的那樣。同樣令我驚訝的是你使用=>作爲參數分隔符。這是一個常見的成語嗎? – 2010-05-25 14:52:29

+1

'split'總是返回一個列表。您可以將一個列表分配給一個散列。 '=>'是「胖逗號」:它具有自動引用前面的空格的效果。 – 2010-05-25 14:54:51

+0

好吧,我明白了,現在我也欣賞解決方案的優雅。今天是美好的一天:我學到了兩件事。 – 2010-05-25 15:05:25

2
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 ") 
+0

我無法讓你的例子工作。請注意,關鍵字只有偶然的子字符串,例如,第三個關鍵字可能是「髮色」。 – 2010-05-25 14:34:05

+0

@ Jean-Denis Muys:是的,我忘記了使嵌套分組無法捕獲。它現在應該工作。這解決了原來的問題。現在爲更通用的情況... – Zaid 2010-05-25 14:42:36

+0

這是非常光滑的(一旦我得到它的工作:) – 2010-05-25 15:28:44

-1

使用文本:: ParseWords。它可能不會完成你想要的所有內容,但是你可以更好地構建它,而不是從頭開始解決整個問題。

0

這是可能的,如果:

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 
+0

條件1是的:該關鍵字集是事先確定的。條件2是否定的:數據在新關鍵字開始時停止,或者在字符串結尾處停止,以先到者爲準。我希望正確的貪心可能會有所幫助。 – 2010-05-25 14:32:12

+0

爲什麼downvote?如果您可以爲標籤和值編寫通用的正則表達式,這是一個非常好的方法,並且非常有用。 – 2010-05-26 17:32:22

2

This Works。

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' 
     ]; 
+0

正則表達式::文法是新的黑色。 – 2010-05-25 15:29:22

+0

呃。可怕的達米安潔具。看起來通常很有光澤,但隨着時間的推移閃耀光芒。最後,如果你需要一個解析器生成器(Parse :: Yapp/Eyapp是我最喜歡的),那麼可能是你最好的選擇。 – tsee 2010-05-25 15:42:09

+0

亞普也很好。 (雖然我們在snowcloning~ ...) – daxim 2010-05-25 15:59:58

3

在字符串下面的循環一旦找到匹配(正火後的字符串)。避免循環的唯一方法是每個關鍵字只能在文本中出現一次。如果是這樣的話,你可以寫

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