2014-06-24 40 views
1

我想提取一部分字符串並將其放入一個新變量中。我在看的字符串是:

maker-scaffold_26653|ref0016423-snap-gene-0.1 

,我想匹配的東西(一個$gene_name變量中)是:

scaffold_26653|ref0016423 

我使用下面的代碼段:

my $gene_name; 
my $scaffold_name; 
if ($gene_name =~ m/scaffold_[0-9]+\|ref[0-9]+/) { 
    $scaffold_name = $1; 
    print "$scaffold_name\n"; 
} 

試圖執行的時候,我發現了以下錯誤:

Use of uninitialized value $scaffold_name in concatenation (.) or string 

我知道這個模式是正確的,因爲如果我使用的$'代替$1我得到

-snap-gene-0.1 

我在一個小的損失的:爲什麼會$1在這裏工作?

+3

如果你想使用匹配的值,你必須在正則表達式中圍繞字符'()'。 – Jens

+0

固定。非常感謝! – Mer

+0

@ysth我已經完成了。 – Jens

回答

4

如果你想使用你必須做出()角落找尋的字符在正則表達式

3

匹配的值要在正則表達式擴大延的回答,()表示一個匿名捕獲組。在捕獲組相匹配的內容被存儲在$ 1-9 +從左至右,因此,例如,

/(..):(..):(..)/ 

上的HH:MM:SS時間字符串將存儲小時,分鐘和秒在$ 1, 2美元,3美元。當然,這開始變得笨拙而不是自我記錄,這樣就可以將結果賦給一個列表,而不是:

my ($scaffold_name) = $gene_name =~ m/(scaffold_[0-9]+[|]ref[0-9]+)/; 
# $scaffold_name now contains 'scaffold_26653|ref0016423' 

my ($hours, $mins, $secs) = $time =~ m/(..):(..):(..)/; 

所以,你的例子可以做直接分配繞過使用$變量

你甚至可以擺脫難看的=〜通過使用綁定的topicalizer:

my $scaffold_name; 
for ($gene_name) { 
    ($scaffold_name) = m/(scaffold_\d+[|]ref\d+)/; 
    print $scaffold_name; 
} 

如果事情開始變得更加複雜,我更喜歡使用命名捕獲組(在介紹Perl v5.10.0):

$gene_name =~ m{ 
    (?<scaffold_name> # ?<name> creates a named capture group 
     scaffold_\d+? # 'scaffold' and its trailing digits 
     [|]   # Literal pipe symbol 
     ref\d+   # 'ref' and its trailing digits 
    ) 
}xms; # The x flag lets us write more readable regexes 
print $+{scaffold_name}, "\n"; 

命名捕獲組的結果存儲在魔術散列%+中。訪問完成就像任何其他哈希查找,捕獲組作爲關鍵。 %+在本地的作用域與$是相同的,所以在大多數情況下它可以作爲它們的替代品。

對於這個特殊的例子來說這太過分了,但是隨着正則表達式開始變得越來越大和越來越複雜,這就節省了你不得不一直向後滾動並且從左到右計算匿名捕獲組的次數來找到那些darn $變量持有你想要的捕獲,或者掃描一個長列表分配以找到在哪裏添加一個新變量來保存插入到中間的捕獲。

我個人的經驗法則是將匿名捕獲的結果分配給3個或更少捕獲的描述性名詞性範圍變量,然後在需要更多條目時切換到正則表達式中使用命名捕獲,註釋和縮進。

+0

非常感謝您的全面回答!我一定會在將來嘗試使用它。 – Mer