2017-06-30 1 views
1

erfasst werden Meine Situation erfordert Rekursion, und ich kann die geschweiften Klammern bereits so anpassen, wie ich sie brauche, aber ich kann sie nicht erfassen der umgebende Text.Übereinstimmender Text, der sich nicht in den geschweiften Klammern befindet, während die Klammern nach

So wäre dies das Beispiel Text sein:

Dies ist foo {{foo}} und {{bar.function ({{demo.funtion ({{innere}} == "Demo") }} und {{bar}} oder "foo")}} more_text {{foo

und ich mein Ergebnis müssen wie folgt aussehen:

0  =>  This is foo 
1  =>  {{foo}} 
2  =>  and 
3  =>  {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} 
4  =>  more_text {{foo 

mit diesem: (\{\{([^{{}}]|(?R))*\}\}) ich in der Lage gewesen passend zu {{foo}} und {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} sehr schön, aber nicht den umgebenden Text, um das Ergebnis zu erreichen, das ich brauche.

Ich habe viele Dinge ausprobiert, aber ohne Erfolg.

Hilfe wäre willkommen.

+0

Was meinen Sie mit "erfassen Sie den umgebenden Text"? – aaaaaa123456789

+0

Bitte klären Sie die Anforderungen. Warum leere Elemente in der Ausgabe? Warum wird das letzte '{{foo' von' more_text' getrennt? –

+0

preg_match_all, anstelle von preg_match. '/ \ {\ {| -0-9a-zA-Z ._] + | \} \} /' Das sind 3 Muster, dann verarbeitest du sie und verfolgst offene, Klammerpaare und Körpertreffer. Dann können Sie verschachteln. – ArtisticPhoenix

Antwort

1

Sie können die folgende Lösung auf der Flagge preg_split und PREG_SPLIT_DELIM_CAPTURE Basis verwenden:

$re = '/({{(?:[^{}]++|(?R))*}})/'; 
$str = 'This is foo {{foo}} and {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} more_text {{foo'; 
$res = preg_split($re, $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); 
print_r($res); 
// => Array 
(
    [0] => This is foo 
    [1] => {{foo}} 
    [2] => and 
    [3] => {{bar.function({{demo.funtion({{inner}} == "demo")}} and {{bar}} or "foo")}} 
    [4] => more_text {{foo 
) 

die PHP demo See.

Das gesamte Muster wird mit der äußeren Erfassungsgruppe erfasst. Deshalb wird beim Hinzufügen von PREG_SPLIT_DELIM_CAPTURE dieser Text (der aufgespalten wird) zum Ausgabe-Array hinzugefügt.

Wenn es unerwünschte leere Elemente gibt, wird PREG_SPLIT_NO_EMPTY Flag sie verwerfen.

Weitere Details:

Muster: Ich entfernt unnötige Fluchten und Symbole aus dem Muster, wie Sie müssen nicht { und } in PHP Regex zu entkommen, wenn der Kontext genug ist für den Rege Motor abzuleiten die { Bedeutung Sie müssen nicht } in allen Kontexten zu entkommen). Beachten Sie, dass [{}] das gleiche wie [{{}}] ist, beide entsprechen einem einzelnen Zeichen, das entweder { oder } ist, egal wie viele { und } Sie in die Zeichenklasse einfügen. Ich verbesserte auch seine Leistung, indem ich den gierigen Quantifizierer + in einen Possessivquantifizierer ++ umwandelte.

Details:

  • ( - Gruppe 1 Start:
    • {{ - 2 aufeinanderfolgende { s
    • (?:[^{}]++|(?R))*-0 oder mehr Sequenzen von:
      • [^{}]++ - 1 oder mehr andere Symbole als { und } (kein Rückzieher in dieses Muster erlaubt ist)
      • | - oder
      • (?R) - versuchen, das gesamte Muster
  • }} passend - eine }} Teilzeichenfolge
  • ) - Gruppe 1 Ende.

PHP Teil:

Wenn eine Zeichenfolge Zeichenüber nur ein Token-Typ verwendet wird, ist es einfach, eine Spaltung Ansatz zu verwenden. Da preg_split in PHP auf eine Regex aufgeteilt werden kann, während der Text beibehalten wird, der angepasst wird, ist es ideal für diese Art von Aufgabe.

Das einzige Problem ist, dass leere Einträge in das resultierende Array kriechen können, wenn die Übereinstimmungen als aufeinanderfolgend oder am Anfang/Ende der Zeichenfolge erscheinen. Daher ist PREG_SPLIT_NO_EMPTY hier gut zu verwenden.

+0

Würde es Ihnen etwas ausmachen, diese Lösung weiter zu erklären? Es funktioniert 100%, aber ich verstehe nicht genau, was genau passiert. – Aborted

+0

Meinst du den PHP-Teil oder den Regex-Teil? Oder beides? –

+0

Also der Regex Teil und wie Splitting war in diesem Fall die beste Lösung. – Aborted

1

würde ich ein Muster wie diese

$patt = '/(?P<open>\{\{)|(?P<body>[-0-9a-zA-Z._]+)|(?P<whitespace>\s+)|(?<opperators>and|or|==)|(?P<close>\}\})/' 

preg_match_all($patt, $text, $matches); 

Der Ausgang viel zu lange verwenden, aber Sie können darüber Schleife und Gegenstände dann nach oben anzupassen, im Grunde ist es die Zeichenfolge tokeninzing.

Es ist wie dieses

array (
0 => 
    array (
     0 => '{{', 
     1 => 'bar.function', 
     2 => '{{', 
     3 => 'demo.funtion', 
     4 => '{{', 
     5 => 'inner', 
     6 => '}}', 
     7 => ' ', 
     8 => '==', 
     9 => ' ', 
     10 => 'demo', 
     11 => '}}', 
     12 => ' ', 
     13 => 'and', 
     14 => ' ', 
     15 => '{{', 
     16 => 'bar', 
     17 => '}}', 
     18 => ' ', 
     19 => 'or', 
     20 => ' ', 
     21 => 'foo', 
     22 => '}}', 
    ), 
'open' => 
    array (
     0 => '{{', 
     1 => '', 
     2 => '{{', 
     3 => '', 
     4 => '{{', 
     5 => '', 
     6 => '', 
     7 => '', 
     8 => '', 
     9 => '', 
     10 => '', 
     11 => '', 
     12 => '', 
     13 => '', 
     14 => '', 
     15 => '{{', 
     16 => '', 
     17 => '', 
     18 => '', 
     19 => '', 
     20 => '', 
     21 => '', 
     22 => '', 
    ), 
), 
'body' => 
    array (
     0 => '', 
     1 => 'bar.function', 
     2 => '', 
     3 => 'demo.funtion', 
     4 => '', 
     5 => 'inner', 
     6 => '', 
     .... 
    ) 
) 

Dann in einer Schleife Sie Spiel sagen kann [0][0]open Tag ist, match [0][1] ist body Spiel [0][3] ist ein weiterer open usw. und durch Spur öffnen und schließen Tags zu halten, kann man arbeiten aus der Verschachtelung. Es wird Ihnen sagen, was enge Übereinstimmung Operator Spiel usw. ein offenes Spiel Körper Spiel ist ...

Alles, was Sie brauchen, ich habe keine Zeit für eine vollständige Aufarbeitung an einer Lösung haben ...

Ein schneller Beispiel wäre ein open gefolgt von einem body gefolgt von einem close ist eine Variable. Und eine open gefolgt von und body und eine andere open ist eine Funktion. p Sie können auch zusätzliche Muster hinzufügen, indem Sie wie folgt (?P<function>function\.) mit dem Rohr hinein wie '/(?P<open>\{\{)|(?P<function>function\.)|... einfügen. Dann könnten Sie Stichworte wie functionforeachblock etc ... was Sie haben.

Ich habe vollwertige Template-Systeme mit dieser Methode geschrieben. In meinem Template-System ich die REGx in einem Array wie diese

[ 'open' => '\{\{', 'function' => 'function\.', .... ] 

bauen und komprimieren es dann zum eigentlichen REGx, macht das Leben einfach ...

$r = []; 
    foreach($patt_array as $key=>$value){ 
    $r[] = '(?P<'.$key.'>'.$value.')'; 
    } 

    $patt = '/'.implode('|', $r).'/'; 

Etc ...

Wenn du folgst.

Verwandte Themen