2016-04-03 57 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()