2011-04-17 25 views
1

我試圖到grep的允許我輸入字符串重複的最大數量似乎並不能得到它的工作。POSIX正則表達式限制重複次數

輸入文件具有三行3,5和分別「PQ」的7次循環。 > = 3,> = 5表達式工作正常,但「3到5之間」表達式{3,5}也顯示了具有7次重複的行。

DEV /> cat input.txt 
pq -- One occurance of pq 
pqpqpqpqpq -five occurances of pq 
pqpqpqpqpqpqpq -- seven occurances of pq 


DEV /> grep "\(pq\)\{3,\}" input.txt 
pqpqpqpqpq -five occurances of pq 
pqpqpqpqpqpqpq -- seven occurances of pq 


DEV /> grep "\(pq\)\{5\}" input.txt 
pqpqpqpqpq -five occurances of pq 
pqpqpqpqpqpqpq -- seven occurances of pq 

DEV /> grep "\(pq\)\{3,5\}" input.txt 
pqpqpqpqpq -five occurances of pq 
pqpqpqpqpqpqpq -- seven occurances of pq 

我做錯了什麼或者這是預期的行爲?

如果這是預期的行爲(如7個PQS的字符串有3-5 PQS之間),

1)在什麼情況下是最大的重複適用? {3,5}和{3,}(大於3)有什麼區別?

2)我可以錨我用「^」,但如果我的字符串不是以「PQ」到底是什麼的正則表達式並有更多的文字嗎?

回答

2

如果某行有七個重複的東西,它也因此包含重複的那件事3-5,並在幾個點,不會少。

使用匹配錨如果你希望錨定匹配。否則,當然,他們不是。

/X{3,}//X{3,5}/和之間的實際差別是多久一個它相匹配的字符串的 - 匹配的程度(或跨度)。如果你正在尋找的是一個布爾型的yes/no響應,並且在你的模式中沒有任何進一步的東西,它沒有什麼區別。實際上,如果知道這樣做是安全的,那麼適度聰明的正則表達式引擎會早點返回。看出差別

一種方法是使用GNU的grep的-o--only匹配選項。觀察:

$ echo 123456789 | egrep -o '[0-9]{3}' 
123 
456 
789 
$ echo 123456789 | egrep -o '[0-9]{3,}' 
123456789 
$ echo 123456789 | egrep -o '[0-9]{3,5}' 
12345 
6789 
$ echo 123456789 | egrep -o '[0-9]{3,5}[2468]' 
123456 
$ echo 123456790 | egrep -o '[0-9]{3,5}[13579]' 
12345 
6789 

要理解最後兩個工作的方式,找到正則表達式引擎的嘗試(包括回溯步驟)很有用。您可以通過這種方式做到這一點使用Perl:

$ perl -Mre=debug -le 'print $& while 1234567890 =~ /\d{3,5}[13579]/g' 
Compiling REx "\d{3,5}[13579]" 
Final program: 
    1: CURLY {3,5} (4) 
    3: DIGIT (0) 
    4: ANYOF[13579][] (15) 
    15: END (0) 
stclass DIGIT minlen 4 
Matching REx "\d{3,5}[13579]" against "1234567890" 
Matching stclass DIGIT against "1234567" (7 chars) 
    0 <> <1234567890>   | 1:CURLY {3,5}(4) 
            DIGIT can match 5 times out of 5... 
    5 <12345> <67890>   | 4: ANYOF[13579][](15) 
            failed... 
    4 <1234> <567890>   | 4: ANYOF[13579][](15) 
    5 <12345> <67890>   | 15: END(0) 
Match successful! 
12345 
Matching REx "\d{3,5}[13579]" against "67890" 
Matching stclass DIGIT against "67" (2 chars) 
    5 <12345> <67890>   | 1:CURLY {3,5}(4) 
            DIGIT can match 5 times out of 5... 
    10 <1234567890> <>   | 4: ANYOF[13579][](15) 
            failed... 
    9 <123456789> <0>   | 4: ANYOF[13579][](15) 
            failed... 
    8 <12345678> <90>   | 4: ANYOF[13579][](15) 
    9 <123456789> <0>   | 15: END(0) 
Match successful! 
6789 
Freeing REx: "\d{3,5}[13579]" 

如果您有關於比賽結束後會發生什麼額外的限制,那麼哪種類型的重複,你可以選擇有很大的不同的。

$ perl -le 'print $& while 1234567890 =~ /\d{3}(?=[13579])/g' 
234 
678 
$ perl -le 'print $& while 1234567890 =~ /\d{3,5}(?=[13579])/g' 
1234 
5678 
% perl -le 'print $& while 1234567890 =~ /\d{3,}(?=[13579])/g' 
12345678 

所以當你有事情要來之後,它可以使一個巨大的:在這裏,我會說,它需要一個奇怪的數字之前結束強加在那裏每場比賽允許完成,約束差價交易。當你只是決定整條線路是否匹配時,可能並不重要。

+0

這是我猜測的一個過於因此,如果它是預期的行爲的問題。」錨定有助於在某些情況下,但如果我的字符串不是結束‘PQ’更新我的問題上面 –

+0

@Rajesh?更新回答以符合您更新的問題。希望這會有所幫助! – tchrist

+0

哇!非常感謝您的詳細解釋。我將再次重溫該示例,因爲我試圖掌握正則表達式的工作原理。再次感謝:) –

1

這是正常現象。字符串「pqpqpqpqpqpqpq」實際上具有三至五次「pq」的重複,然後幾個更好的措施。您可能想要嘗試固定您的正則表達式,如^\(pq\)\{3,5\}$


編輯,以匹配編輯問題:

  1. 最大的是適用於所有情況。現在發生的事情是,grep匹配「pq」的7次重複中的5次(最有可能是前5次),並且因爲它找到了匹配項,所以打印出該行。
  2. 你必須找出一種方法來改變你的正則表達式,以匹配你想要的和不匹配的東西。例如,要匹配以3-5次重複的「pq」開頭的行,您可以執行如下操作:^\(pq\){3,5}\($|[^p]|p$|p[^q]\)。該匹配符合3-5「pq」,緊跟在行尾或任何字符以外的「p」或「p」 - 後面跟隨行尾或「p」 - 跟隨 - 通過任何字符 - 其他 - 不包括─「q」。
+0

這也是我的猜測之一,因此是否是預期行爲的問題「。在某些情況下錨定有助於解決問題,但如果我的字符串不以「pq」結尾呢? - 更新了我的問題 –

+0

@Rajesh:更新了答案以回答您編輯的問題。 – Anomie

+0

謝謝你的答案! –