2012-05-01 34 views
0

我試圖從字符串中提取4個信息塊。該字符串是包含擴展名的文件的名稱。第一個組可以包含任何有效的字符,直到達到第二個組之前的空間。第二組數據將包含在一組方括號內的4個數字。該組由一個空格分隔。第三組可以是3或4個數字,後跟字母「p」。這些組還與前一組分隔開。最後一組是文件擴展名。Perl正則表達式 - 捕獲所有字符,直到出現模式

下面是一個例子:

This, could be ['a'] s(@m)pl3 file name_with any characters [1923] (720p).avi 

這將然後需要被解析爲:

$1 = This, could be ['a'] s(@m)pl3 file name_with any characters 
$2 = 1923 
$3 = 720p 
$4 = avi 
+0

我只是意識到如何還不清楚我最初發布了。我還注意到,在我之前的假設中我犯了一個錯誤。爲了清晰起見,我繼續完整地重新編寫它。希望這會有所幫助,對於之前的困惑感到抱歉。 – TehTechGuy

+0

對不起,當我編輯評論時,這是我的不快。這些標籤被添加,我忘了刪除密切的標籤。 – TehTechGuy

回答

3

perldoc perlreref見。

下面是一個例子更新要考慮到您的樣本字符串:

#!/usr/bin/env perl 

use strict; use warnings; 

my $x = q{This, could be ['a'] s(@m)pl3 file name_with any characters [1923] (720p).avi}; 

my $pat = qr{ 
    \A 
    (.+?) 
    [ ] 
    \[ ([0-9]{4}) \] 
    [ ] 
    \(([0-9]+ p) \) 
    [.] 
    (.+) 
    \z 
}x; 

print "---$_---\n" for $x =~ $pat; 

輸出:

---This, could be ['a'] s(@m)pl3 file name_with any characters--- 
---1923--- 
---720p--- 
---avi---
+0

不是「(任何字符集),」簡單(。*?) – MarcoS

+0

@MarcoS肯定的,但也將匹配空間和製表符這大概是沒有文件名的一部分。 – Sylverdrag

+0

我以某種方式閱讀任何*非空格*字符,但我可能是錯的。 –

1

我會寫這樣的(.*?) (\[\d{4}\]) (\(\d+p\))\.(.*)

正則表達式沒有測試,它可以寫得更好:)

+0

謝謝!這正是我所需要的,正如我最初的迴應所指定的那樣。事實上,我編輯它是這樣的:(。*?)\ [(\ d {4})\] \((\ d + P)\)\後我發現我並不需要的平方。(*)。括號和括號。 – TehTechGuy

0

我不使用Per L,所以我的正則表達式可能需要一些調整,但據我所知:

(any set of characters) = \S* 
(a space) = \s+ 
('[' + 4 numbers + ']') = \[[0-9]{4} 
(a space) = \s+ 
('(' + an unknown number of numbers + 'p)') = \([0-9]+p\) 
(a period) = \. 
(file extension) = .{2,5} 
0

這就像你正在試圖解析一個文件名。如果思南猜中它看起來是這樣的:

$x = 'a b c d e [1234] (1080p).mov' 

現在,你可以寫一個正則表達式來解析這一點,但具有不同的特點和複雜的正則表達式,它可能是痛苦的維護,易折斷。那麼爲什麼不讓它更容易和使用split

my @fields = split ' ', $x; 

您也可以分割單空間/ /,但你如果您有多個場所的任何地方冒險多個空字段。而且它不會去掉換行符。

這一切都取決於你想捕捉什麼領域,當然,但由於你沒有提到,我不能幫你。請注意,您以後可以解析數組太:

my @nums = grep /\d/, @fields;  # anything with numbers 
my ($tag) = grep /\[\d+\]/, @fields; # catch first [1234] type field 

的一點是,現在正則表達式更容易編寫和維護。

如果你是依靠從字符串的結尾向後做匹配,您可以利用組合的reverse功能與split,如:

my $xrev = reverse $x; 
my @fields = split ' ', $xrev, 3; 

其中「3」是一個極限有多少個字段被創建,所以@fields現在只包含三個字符串。

3

無論Perl與否,有時正則表達式的問題都是它的貪婪。比方說,我想捕捉一個人的名字和字符串是這樣的:

Bob Baker 

我可以使用正則表達式:

sed 's/^\(.*)\ .*$/\1/' 

這將與鮑勃工作貝克,但不與鮑勃巴里貝克。問題是,我的正則表達式是貪婪的,將選擇所有的字符,直到最後的空間,所以我最終不會與BobBob Baker。要解決這個問題的常用方法是除了你不希望一個指定的所有字符

sed 's/^\([^ ]*)\ .*$/\1/' 

在這種情況下,我指定任何字符集包括空間。這會將Bob BakerBob Rudolph Baker都更改爲Bob

Perl有另一種指定非貪婪正則表達式的方法。在Perl中,你將?添加到你想要不貪婪的子表達式中。在上面的例子中,這兩個將包含Bob Barry Baker字符串變成只是Bob

$string =~ s/^([^ ]+) .*$/$1/; 
$string =~ s/^(.+?) .*$/$1/; 

順便說一句,這些相當於

隨着一切,但空間正則表達式,我可以這樣做:

$string =~ /^([^ ]+)()(\[\d{4}\])()(\(\d+p\))(\.)([^.]+)/ 

與非貪婪預選賽:

$string =~ /^(.+?)()(\[\d{4}\])()(\(\d+p\))(\.)(.*)/ 

,並使用x預選賽它允許你把相同的正則表達式放在多行上,這很好,因爲你可以添加註釋來幫助解釋你在做什麼:

$string =~/
    ^(.+?)     #Any set of characters (non-greedy) 
    ([ ])     #Space 
    (\[\d{4}\])    #[1959] 
    ([ ])     #Space 
    (\([0-9]+p\))   #(430p) 
    [.]      #Period 
    ([^\.]+)     #File Suffix (no period) 
/x 

而且,在這一點上,您不妨遵循Damian Conway的最佳實踐關於Perl正則表達式的建議。

$string =~/
    \A     #Start of Regular Expression Anchor 
    (.+?)   #Any set of characters (non-greedy) 
    ([ ])   #Space 
    (\[ \d{4} \]) #[1959] 
    ([ ])   #Space 
    (\([0-9] +p \)) #(430p) 
    ([.])   #Period 
    ([^\.]+)   #File Suffix (no period) 
    \Z     #End of string anchor 
/xm; 

由於x忽略所有空白,我可以在同一行亞組之間甚至添加空格。在這種情況下,(.*+?)只比(.*+?)更清潔。是否(\([0-9] +p \))(\([0-9]+p \))甚至(\([0-9]+p\))更容易理解取決於您。

而且,是的答案看起來非常像Sinan's答案。

順便說一句,作爲思南顯示,使用非貪婪的正則表達式預選賽能夠解析a b c d e [1234] (1080p).mov在使用一切,不包括空格子表達式不會。這就是爲什麼我說他們不一樣。

+0

你對事物的解釋非常有幫助。我同意,將意見提供給旁邊可以更容易地解釋發生的事情。我確實注意到在最後一個代碼塊的「#Period」行中缺少一個右括號。我也不能通過使用「$ string =〜/」來實現它,但是在將它改爲「$ string = qr {」之後它工作。 – TehTechGuy

+0

'$ string =〜/../'假定你要解析的字符串是'$ string'。 'my $ regex = qr(..)'把正則表達式保存在'regex'中,所以你可以在後面使用'$ string =〜/ $ regex /;'。我修復了缺失的括號。當您手動複製東西時會發生這樣的錯誤。 –

相關問題