2016-06-12 8 views
0

Ich habe eine Template-Engine. Tpl-Dateien analysieren. Aber wenn tpl-Dateien eine Menge {if}, {foreach} oder {sprache} Blöcke haben, preg_match crush Apache.preg_match crush apache

Das meine preg_match-Funktion;

preg_match_all('$\{(if|foreach)[\s]*(.*?)[\s]*\}((?:[^{]*(?:\{(?!\/?(if|foreach)[^}]*\})[^{]*)*|(?R))*)\{\/\1\}$iu',$content,$output); 

Und das ist Apache-Logs

[Sun Jun 12 21:04:41.135620 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00428: Parent: child process 7620 exited with status 255 -- Restarting. 
[Sun Jun 12 21:04:41.235425 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00455: Apache/2.4.9 (Win64) PHP/5.5.12 configured -- resuming normal operations 
[Sun Jun 12 21:04:41.236426 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00456: Apache Lounge VC11 Server built: Mar 16 2014 12:42:59 
[Sun Jun 12 21:04:41.236426 2016] [core:notice] [pid 1888:tid 552] AH00094: Command line: 'c:\\wamp\\bin\\apache\\apache2.4.9\\bin\\httpd.exe -d C:/wamp/bin/apache/apache2.4.9' 
[Sun Jun 12 21:04:41.284459 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00418: Parent: Created child process 9668 
[Sun Jun 12 21:04:41.642877 2016] [mpm_winnt:notice] [pid 9668:tid 452] AH00354: Child: Starting 64 worker threads. 
[Sun Jun 12 21:04:42.047450 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00428: Parent: child process 9668 exited with status 255 -- Restarting. 
[Sun Jun 12 21:04:42.147702 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00455: Apache/2.4.9 (Win64) PHP/5.5.12 configured -- resuming normal operations 
[Sun Jun 12 21:04:42.147702 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00456: Apache Lounge VC11 Server built: Mar 16 2014 12:42:59 
[Sun Jun 12 21:04:42.147702 2016] [core:notice] [pid 1888:tid 552] AH00094: Command line: 'c:\\wamp\\bin\\apache\\apache2.4.9\\bin\\httpd.exe -d C:/wamp/bin/apache/apache2.4.9' 
[Sun Jun 12 21:04:42.194580 2016] [mpm_winnt:notice] [pid 1888:tid 552] AH00418: Parent: Created child process 10824 
[Sun Jun 12 21:04:42.487866 2016] [mpm_winnt:notice] [pid 10824:tid 452] AH00354: Child: Starting 64 worker threads. 

Aber wenn ich versuche, regex101.com, seine succesfuly Matching ohne Fehler. https://regex101.com/r/uW8rZ8/3

+0

Ich denke, diesen Teil [ '\ {(falls | foreach) [\ s] * (*. ?) [\ s] * \} '] (https://regex101.com/r/rN1kM8/1) verursacht eine Menge Backtracking. Alternative: ['{(wenn | foreach) \ s * ([^}] * [^] \ s]) \ s *}'] (https://regex101.com/r/rN1kM8/2) aber es gibt gute Antworten schon (: –

Antwort

1

Selbst wenn Ihr Muster mit regex101 funktioniert, sind Sie in der Nähe des katastrophalen bactracking. Der Grund, warum Sie Muster mit regex101 und nicht mit Ihrem Server arbeiten, ist einfach: Konfigurationen sind nicht die gleichen.

Zwei Dinge sind in Ihrem Muster fehlen:

  • die Verwendung von possessiven Quantoren (oder Atomgruppen) Rückzieher zu verbieten, wo es nicht sinnvoll ist.
  • entrollen Dinge wie (?:A|B)* zu A*+(?:BA*)*+, um den Wechsel zu vermeiden und die Anzahl der Schritte zu reduzieren.

diese Hinweise Nach Ihre Muster über 3x effizienter machen:

~ 
{ (if\b|foreach\b) \s*+ 
([^\s}]*+ (?:\s+[^\s}]+)*+) \s* } 
(
    [^{]*+ 
    (?: { (?!/?if\b|/?foreach\b) [^{]* 
     | (?R)      [^{]*)*+ 

) 
{/\1} 
~ixu 

demo

1

Regex101 funktioniert möglicherweise ohne Fehler, aber es funktioniert nicht gut. Wenn Sie einen Blick darauf werfen, heißt es: 2 matches - 10792 steps, was bedeutet, dass Ihre Regex wahrscheinlich katastrophal Backtracking ist. Wenn das nicht der Fall ist, verwenden Sie wahrscheinlich nicht das richtige Tool. Haben Sie darüber nachgedacht, einen tatsächlichen Parser zu verwenden? Eine, die entworfen wurde, um rekursives Matching zu behandeln?

Wenn Sie immer noch das Gefühl haben, dass mit Regexes getan werden muss, müssen Sie einige Fehler beheben.

Ich bin nicht vertraut mit der Einrichtung müssen Sie direkt mit den Fehlern helfen Sie erhalten (sind sie sogar Fehler?), Aber ich denke, dass Sie einige drängendere Probleme lösen müssen, bevor Sie die anderen angehen können Probleme. Es ist möglich, dass dieser Prozess das Problem löst, das Sie haben, da es sehr wahrscheinlich verwandt ist.

Das größte Ding für mich jetzt ist Ihre Regex fehlt Lesbarkeit. Ich habe keine Ahnung, was deine Regex macht. Und ich bin kein durchschnittlicher Programmierer ... Ich LIEBE Regexes, und ich kann sie normalerweise leicht lesen. Aber nicht dieser. (Ein Teil des Problems kann auch die Tatsache sein, dass es nicht wirklich klar warum Sie diese Regex verwenden.)

Mein erster Vorschlag den x Modifikator verwenden wäre, mit dem Sie Abstand verwenden kann, wie Sie würde in einem normalen Programm. Ich habe Ihre ursprüngliche regex modifizierten Abstand zu verwenden, und ich habe auch eine übermäßige Schrägstriche entfernt:

{(if|foreach) 
[\s]* 
(.*?) 
[\s]*} 
((?: 
    [^{]* 
    (?:{ 
    (?!/? 
     (if|foreach)[^}]*} 
    ) 
    [^{]* 
)*|(?R))* 
) 
{/\1} 

ich geschrieben habe, eine ähnliche rekursive Parser mit regulären Ausdrücken in der Vergangenheit, so habe ich einige Erfahrung mit dieser Art von Ding. Soweit ich mich erinnere, war mein Parser schneller, und er war viel besser lesbar (wenn er ähnlich wie ein BNF-artiger Parser läuft). Ich denke, dass ich jetzt, wie etwas, das schneller ist, basiert weg von meinem Parser:

$re = "` 
{(if)  ((?&exp))}(*PRUNE)\s*((?&line)*)\s*(*PRUNE){/if}| 
{(foreach)((?&exp))*}(*PRUNE)\s*((?&line)*)\s*(*PRUNE){/foreach} 
|(?&other)+ 

|(*F)(?: 
    (?'line' (?&if)|(?&for)|(?&other)+) 
    (?'if' {if  (?&exp)}(*PRUNE)\s*(?&line)*\s*(*PRUNE){/if}) 
    (?'for' {foreach(?&exp)}(*PRUNE)\s*(?&line)*\s*(*PRUNE){/foreach}) 
    (?'other' ([^{]+|{)(?! (/?if|/?foreach))) 
    (?'exp' [^}]*) 
)`xis"; 
+0

Danke für den Rat, ich arbeite daran – redfox9999