2 Stimmen

PHP regex funktioniert nicht - gibt NULL auf dem lokalen Server zurück, funktioniert aber korrekt auf anderen

Ich habe folgende Regex:

/\{\s?joomla-tag\s+(.*<+.+>+.*)\s?\}/is

und den folgenden Code:

$regex = "/\{\s?joomla-tag\s+(.*<+.+>+.*)\s?\}/is";
$replace = '<div class="someclass">$1</div>';
$text = preg_replace( $regex, $replace, $text );

Aber leider kann er nicht mit dem folgenden Code übereinstimmen (obwohl er das sollte):

.... many html lines .......
<p>123{joomla-tag Lore<strong>m</strong> ip</p>
<p>sum dolor sit amet}</p>
.... many html lines .......

Sehen Sie sich das echte Beispiel an: http://pastebin.com/WSQyrmxd

Was ist falsch: ein regulärer Ausdruck oder etwas anderes? Könnten Sie mir bitte die richtige Variante empfehlen? In RegExr funktioniert alles reibungslos, aber nicht in PHP.

Auf einem lokalen Server, erhalte ich einfach NULL nach preg_replace


EDIT: Endlich habe ich eine Lösung gefunden: (Danke, sg3s für eine Idee) http://www.pelagodesign.com/blog/2008/01/25/wtf-preg_replace-returns-null/

1 Stimmen

Muss der reguläre Ausdruck sein.

0 Stimmen

Ich glaube nicht, dass Sie die \{

0 Stimmen

Sie sind notwendig, ich muss mit {joomla-tag ..... }

5voto

Alan Moore Punkte 70949

Sie sagen, Sie hätten das Problem gelöst, aber wenn Ihre Lösung darin bestand, die backtrack_limit Einstellung, ist das keine Lösung. Wahrscheinlich bereiten Sie sich damit später sogar noch größere Probleme. Sie müssen herausfinden warum es macht so viele Rückschritte.

Nach \{\s?joomla-tag\s+ lokalisiert den Anfang des Tags, den ersten .* verschlingt zunächst den Rest des Dokuments. Dann beginnt er, sich zurückzuziehen und zu versuchen, den Rest der Regex passen zu lassen. Wenn er einen Punkt erreicht, an dem <+ übereinstimmen können, wird die .+ verbraucht wieder den Rest des Dokuments, und eine weitere Welle von Rückverfolgungen beginnt. Und mit einer weiteren .* Danach lässt du ihn eine lächerliche Menge unnötiger Arbeit verrichten.

Dies ist der Grund für die Faustformel,

Verwenden Sie nicht das Metazeichen Punkt (insbesondere .* o .+ ), wenn Sie etwas Spezifischeres verwenden können. Wenn Sie den Punkt verwenden, sollten Sie ihn nicht im Einzeilen- oder DOTALL-Modus verwenden (d. h. die /s Modifikator oder dessen Inline, (?s) Form).

In diesem Fall wissen Sie, dass die Übereinstimmung an der nächsten schließenden Klammer enden sollte ( } ), so dass sie nicht mit den Klammern davor übereinstimmt:

\{\s?joomla-tag\s+([^}]*)\}

0 Stimmen

Ja! Der ursprüngliche Ausdruck hat viel Raum für Verbesserungen, was das Backtracking betrifft. +1

0 Stimmen

+1. Eine Frage allerdings: Ist die Verwendung der nicht-gierigen .*? Hilfestellung geben, damit sie nicht den Rest des Dokuments verschlingt?

0 Stimmen

Wenn die Schließung } vorhanden ist, .*? auf jeden Fall effizienter sein wird als .* . Wenn es fehlt, .*? wird bis zum Ende des Dokuments fortgesetzt, bevor es aufgibt.

4voto

ridgerunner Punkte 32111

Klingt so, als könnte das ein: pcre.recursion_limit Fehler, weil die PCRE-Regex-Engine keinen Stack mehr hat. Ich habe das schon einmal gesehen (aber normalerweise sind die Symptome schwerwiegender - z.B. ein kompletter Absturz des Webservers!) Beachten Sie, dass diese Art von Problem häufig auf einem lokalen Server und nicht auf einem entfernten Server auftritt, insbesondere wenn auf dem lokalen System Apache unter Windows läuft (Die Win32-Version von httpd.exe hat nur 256KB Stapelplatz).

preg_replace() 収益 NULL wenn es auf einen Fehler in der PCRE-Bibliothek stößt. Sie können die preg_last_error() Funktion, um den letzten Fehler zu ermitteln und eine Meldung wie folgt auszugeben:

   $pcre_err = preg_last_error();  // PHP 5.2 and above.
    if ($pcre_err === PREG_NO_ERROR) {
        $msg = 'Successful non-match.';
    } else {
        // preg_match error!
        switch ($pcre_err) {
            case PREG_INTERNAL_ERROR:
                $msg = 'PREG_INTERNAL_ERROR';
                break;
            case PREG_BACKTRACK_LIMIT_ERROR:
                $msg = 'PREG_BACKTRACK_LIMIT_ERROR';
                break;
            case PREG_RECURSION_LIMIT_ERROR:
                $msg = 'PREG_RECURSION_LIMIT_ERROR';
                break;
            case PREG_BAD_UTF8_ERROR:
                $msg = 'PREG_BAD_UTF8_ERROR';
                break;
            case PREG_BAD_UTF8_OFFSET_ERROR:
                $msg = 'PREG_BAD_UTF8_OFFSET_ERROR';
                break;
            default:
                $msg = 'Unrecognized PREG error';
                break;
        }
    }
    echo($msg);

Ich habe diesen Fehler im Detail erklärt und Antworten auf damit zusammenhängende Fragen gegeben. Siehe:

RegExp in der Funktion preg_match liefert Browser-Fehler

PHP regex: ist etwas falsch mit diesem Code?

Minimierung der endgültigen HTML-Ausgabe durch reguläre Ausdrücke mit CodeIgniter

Viel Glück!

2voto

poke Punkte 338075

Es funktioniert bei mir .

Beachten Sie, dass Ihre Ersetzung vom HTML-Standpunkt aus gesehen keine gültige Struktur erzeugt.

Verwendung des Volltextes

Es ist immer noch funktioniert bei mir sogar mit dem mitgelieferten vollständigen HTML-Beispiel. Es muss also etwas mit Ihrem anderen Code nicht stimmen. Vielleicht sollten Sie die vollständige Fehlerausgabe aktivieren, um zu sehen, ob es ein anderes Problem gibt.

0 Stimmen

Ja, ich weiß. Aber das wird weiter behandelt werden. Jetzt muss ich das zum Laufen bringen

0 Stimmen

Wirklich seltsam... Kann es an der Kodierung liegen?

0 Stimmen

Auf einem lokalen Server, erhalte ich einfach NULL nach preg_replace

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X