2016-04-03 63 views
1

我寫了一個正則表達式,我在rubular.com中測試過,它返回了4個匹配項。測試的主題可以在這裏找到http://pastebin.com/49ERrzJN和PHP代碼如下。由於某些原因,PHP代碼只返回前兩個匹配項。如何使它匹配所有4?這似乎與貪婪等有關。PHP preg_match_all問題

$file = file_get_contents('x.txt'); 
preg_match_all('~[0-9]+\s+(((?!\d{7,}).){2,20})\s{2,30}(((?!\d{7,}).){2,30})\s+([0-9]+)-([0-9]+)-([0-9]+)\s+(F|M)\s+(.{3,25})\s+(((?!\d{7,}).){2,50})~', $file, $m, PREG_SET_ORDER); 
foreach($m as $v) echo 'S: '. $v[1]. '; N: '. $v[3]. '; D:'. $v[7]. '<br>'; 
+2

你究竟想要提取什麼? – Druzion

+0

Ruby Ruby不是rubular.com嗎? – Laurel

+0

@Druzion:姓名,出生日期,性別最重要 – pedmillon

回答

2

你的正則表達式非常slooooooow。在regex101.com上試用後,我發現它會在PHP上超時(但不管是什麼原因,不是JS)。我很確定超時發生在大約50000步。實際上,現在爲什麼你不使用在線PHP正則表達式測試程序是有道理的。

我不知道,如果這是你的問題的根源,但there is a default memory limit in PHP:

memory_limit的[預設:] 「128M」

[歷史記錄:] 「8M」 PHP 5.2.0之前在PHP「16M」 5.2.0

如果使用m ultiline修改(我假設preg_match_all實質上增加了g葉形修改),你可以使用這個表達式,僅需要1282個步驟,以網絡ND所有4場比賽:

^ [0-9]+\s+(((?!\d{7,}).){2,20})\s{2,30}(((?!\d{7,}).){2,30})\s+([0-9]+)-([0-9]+)-([0-9]+)\s+(F|M)\s+(.{3,25})\s+(((?!\d{7,}).){2,50})

事實上,只有2個是我添加的字符。它們在一開始就是主角^和文字空間。

+0

謝謝,加了2個字符並用m修飾符做了這個工作 – pedmillon

+0

模式問題與PHP內存限制無關。 –

1

如果你必須編寫一個長模式,首先要做的是讓它可讀。爲此,請使用允許註釋和自由間距的詳細模式(x修飾符),並使用命名捕獲。

然後,你需要做的精確描述你正在尋找:

  • 你的目標需要一整行=>使用錨^$與調節器M,並使用\h(只包含水平空白)而不是\s類。
  • 而不是使用這種低效的子模式(?:(?!.....).){m,n}來描述您的字段不能包含什麼,請描述該字段可以包含的內容。
  • 在需要時使用原子組(?>...)而不是非捕獲組以避免無用的回溯。
  • 在一般情況下,採用精確的字符類可以避免很多問題

模式:

~ 
^ \h*+ # start of the line 
# named captures       # field separators 
(?<VOTERNO>  [0-9]+     ) \h+ 
(?<SURNAME>  \S+ (?>\h\S+)*?   ) \h{2,} 
(?<OTHERNAMES> \S+ (?>\h\S+)*?   ) \h{2,} 
(?<DOB>   [0-9]{2}-[0-9]{2}-[0-9]{4}) \h+ 
(?<SEX>   [FM]      ) \h+ 
(?<APPID_RECNO> [0-9A-Z/]+    ) \h+ 
(?<VILLAGE>  \S+ (?>\h\S+)*   ) 
\h* $ # end of the line 
~mx 

demo

如果你想知道哪裏出了問題用一個模式,你可以使用功能preg_last_error()