2009-03-29 15 views
13

Ich versuche, eine Zeichenfolge übereinzustimmen, die über mehrere Zeilen angezeigt werden kann. Es beginnt und endet mit einer bestimmten Zeichenfolge:Einschließlich neuer Zeilen in PHP preg_replace Funktion

{a}some string 
can be multiple lines 
{/a} 

Kann ich alles zwischen {a} und {/a} mit einem regex greifen? Es scheint die. passt nicht zu neuen Zeilen, aber ich habe folgendes ohne Glück ausprobiert:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/', 'X', $template, -1, $count); 
echo $count; // prints 0 

Es passt. oder \ n wenn sie allein sind, aber nicht zusammen!

Antwort

31

Verwenden Sie die s modifier:

$template = preg_replace($'/\{a\}([.\n]+)\{\/a\}/s', 'X', $template, -1, $count); 
//            ^
echo $count; 
+0

Awesome, ich wusste, es wäre so einfach! – DisgruntledGoat

+0

Auch ich habe gerade festgestellt, dass diese Info auf der PHP-Website ist, obwohl ich noch nie zuvor bei der Suche gefunden habe ... http://www.php.net/manual/en/reference.pcre.pattern.modifiers .php – DisgruntledGoat

3

Von http://www.regular-expressions.info/dot.html:

"Der Punkt entspricht ein einzelnes Zeichen, ohne Sorge, was das Zeichen Die einzige Ausnahme sind Newline Zeichen."

müssen Sie Ihrem Ausdruck ein trailing/s-Flag hinzufügen.

6

Ich denke, Sie haben mehr Probleme als nur den Punkt Zeilenumbrüche nicht übereinstimmen, aber lassen Sie mich mit einer Formatierungsempfehlung beginnen. Sie können fast jedes Interpunktionszeichen als Regex-Begrenzer verwenden, nicht nur den Schrägstrich ('/'). Wenn Sie ein anderes Zeichen verwenden, müssen Sie keine Schrägstriche innerhalb der Regex entziffern. Ich verstehe "%" ist beliebt bei PHPers; das würde Ihr Muster Argument machen:

'%\{a\}([.\n]+)\{/a\}%' 

Nun, der Grund, dass regex nicht funktioniert, wie Sie ist beabsichtigt, da der Punkt seine besondere Bedeutung verliert, wenn es innerhalb einer Zeichenklasse (die eckigen Klammern) erscheint - so [.\n] entspricht nur einem Punkt oder einem Zeilenvorschub. Was Du gesucht war (?:.|\n), aber ich würde den Wagenrücklauf sowie den Zeilenvorschub empfohlen passend:

'%\{a\}((?:.|[\r\n])+)\{/a\}%' 

Das ist, weil das Wort „Newline“ auf den Unix-Stil beziehen kann „\ n“, Windows-Stil "\ r \ n" oder älter-Mac-Stil "\ r". Jede gegebene Webseite kann irgendwelche von diesen oder eine Mischung von zwei oder mehr Arten enthalten; eine Mischung aus "\ n" und "\ r \ n" ist sehr verbreitet. Aber mit/s-Modus (auch als einzeilige oder DOTALL Modus bekannt), brauchen Sie nicht zu befürchten, dass:

'%\{a\}(.+)\{/a\}%s' 

Allerdings gibt es ein anderes Problem mit dem ursprünglichen Regex, die in diesem noch vorhanden ist: die + ist gierig. Das bedeutet, wenn es mehr als eine {a}...{/a} Sequenz im Text gibt, wird die Regex das erste Mal angewendet, wenn sie alle übereinstimmt, von der ersten {a} bis zur letzten {/a}. Der einfachste Weg, dies zu beheben, ist den + ungreedy (auch bekannt als „faul“ oder „nur ungern“) zu machen, indem ein Fragezeichen angehängt:

'%\{a\}(.+?)\{/a\}%s' 

Schließlich, ich weiß nicht, was den ‚$ machen 'vor dem Eröffnungszitat Ihres Musterarguments. Ich mache kein PHP, aber das sieht für mich wie ein Syntaxfehler aus. Wenn mich jemand in dieser Angelegenheit unterrichten könnte, würde ich es begrüßen.

+0

Oh, das muss ein Tippfehler sein - ich habe ursprünglich dort eine Variable verwendet und sie für dieses Beispiel durch eine Zeichenfolge ersetzt. – DisgruntledGoat

+0

Das war eine großartige Erklärung. Prost dafür. – craignewkirk