Wie kann ich Regex validieren?

73

Ich möchte die Gültigkeit eines regulären Ausdrucks in PHP testen, vorzugsweise bevor er verwendet wird. Ist der einzige Weg, dies zu tun, tatsächlich ein a zu versuchen preg_match()und zu sehen, ob es zurückkehrt FALSE?

Gibt es eine einfachere / richtige Möglichkeit, einen gültigen regulären Ausdruck zu testen?

Ross McFarlane
quelle
Wenn es nicht im Code enthalten sein muss, können Sie zu regexr.com gehen, Ihren regulären Ausdruck einfügen und den Text eingeben, mit dem Sie ihn vergleichen.
Kao
Warum willst du preg_match () nicht gegen false prüfen?
rubo77
1
Sieht so aus, als wäre ich zu spät zur Party gekommen
Baba,
Einige Antworten berücksichtigen nicht, dass der zu validierende reguläre Ausdruck möglicherweise von der Eingabe eines Administrators einer App stammt. Möglicherweise verfügt die App über eine Tabelle "contact_types" mit einem Feld "regulärer Ausdruck" ...
J. Bruni

Antworten:

139
// This is valid, both opening ( and closing )
var_dump(preg_match('~Valid(Regular)Expression~', null) === false);
// This is invalid, no opening ( for the closing )
var_dump(preg_match('~InvalidRegular)Expression~', null) === false);

Da der Benutzer pozs gesagt, auch berücksichtigen setzt @vor preg_match () ( @preg_match()) in einer Testumgebung Warnungen oder Hinweise zu verhindern.

Um ein RegExp zu validieren, führen Sie es einfach aus null (Sie müssen die Daten, gegen die Sie testen möchten, nicht im Voraus kennen) . Wenn es explizit false ( === false) zurückgibt , ist es fehlerhaft. Andernfalls ist es gültig, obwohl es mit nichts übereinstimmen muss.

Sie müssen also keinen eigenen RegExp-Validator schreiben. Es ist Zeitverschwendung ...

CodeAngry
quelle
1
Nur eine Vermutung: Das OP sagte: "Ich möchte die Gültigkeit eines regulären Ausdrucks in PHP testen, vorzugsweise bevor er verwendet wird. "
JDB erinnert sich noch an Monica
7
@ Cyborgx37 Na und? Ich gab ihm die Lösung mit einem NULL. Sie müssen jetzt nicht die Zeichenfolge verwenden, für die Sie sie verwenden möchten. Sie müssen nur das Muster kennen, um zu sehen, ob es korrekt ist. Ob es passt oder nicht ... das ist eine andere Geschichte und hängt von Ihrer Zielzeichenfolge ab. Was habe ich falsch gesagt?
CodeAngry
1
Ich habe dich nicht herabgestimmt ... nur erraten, warum jemand haben könnte. Ich denke deine Antwort ist in Ordnung.
JDB erinnert sich noch an Monica
5
Beachten Sie, dass im Fall eines ungültigen regulären Ausdrucks Ihr Code eine Warnung anzeigt, die zu schade ist, um nur den Ausdruck zu testen - Sie sollten schützen, mit dem Sie preg_match()anrufen@
pozs
2
Der Operator zur Fehlerunterdrückung ist keine gute Lösung, da Probleme beim Testen von Frameowrks auftreten und der Operator "@" zum Testen deaktiviert wird. Als Workaround können Sie "set_error_handler" vor und "restore_error_handler" nach diesem Test verwenden;)
mabe.berlin
24

Ich habe eine einfache Funktion erstellt, die zum Überprüfen von Preg aufgerufen werden kann

function is_preg_error()
{
    $errors = array(
        PREG_NO_ERROR               => 'Code 0 : No errors',
        PREG_INTERNAL_ERROR         => 'Code 1 : There was an internal PCRE error',
        PREG_BACKTRACK_LIMIT_ERROR  => 'Code 2 : Backtrack limit was exhausted',
        PREG_RECURSION_LIMIT_ERROR  => 'Code 3 : Recursion limit was exhausted',
        PREG_BAD_UTF8_ERROR         => 'Code 4 : The offset didn\'t correspond to the begin of a valid UTF-8 code point',
        PREG_BAD_UTF8_OFFSET_ERROR  => 'Code 5 : Malformed UTF-8 data',
    );

    return $errors[preg_last_error()];
}

Sie können diese Funktion mit dem folgenden Code aufrufen:

preg_match('/(?:\D+|<\d+>)*[!?]/', 'foobar foobar foobar');
echo is_preg_error();

Alternative - Online-Tester für reguläre Ausdrücke

Wahyu Kristianto
quelle
2
Dies ist nur ein Umschlag preg_last_errorspeziell für die englische Sprache.
Alin Purcaru
Dies sagt Ihnen übrigens nicht wirklich, ob Regex gültig ist oder nicht. Beachten Sie Folgendes: php> preg_match ("/ aaa", ""); php> echo preg_last_error (); 0
Alex N.
PHP 7 hinzugefügt PREG_JIT_STACKLIMIT_ERROR. Siehe die Dokumente .
mbomb007
15

Wenn Sie einen regulären Ausdruck dynamisch testen möchten, preg_match(...) === falsescheint dies Ihre einzige Option zu sein. PHP verfügt nicht über einen Mechanismus zum Kompilieren regulärer Ausdrücke, bevor sie verwendet werden.

Möglicherweise ist preg_last_error auch eine nützliche Funktion.

Wenn Sie jedoch einen regulären Ausdruck haben und nur wissen möchten, ob dieser gültig ist, bevor Sie ihn verwenden, stehen eine Reihe von Tools zur Verfügung. Ich fand rubular.com angenehm zu bedienen.

Alin Purcaru
quelle
6

Sie können überprüfen, ob es sich bei diesem Albtraum eines regulären Ausdrucks um einen syntaktisch korrekten regulären Ausdruck handelt, wenn Ihre Engine die Rekursion unterstützt (PHP sollte dies tun).

Sie können jedoch nicht algorithmisch feststellen, ob die gewünschten Ergebnisse erzielt werden, ohne es auszuführen.

Von: Gibt es einen regulären Ausdruck, um einen gültigen regulären Ausdruck zu erkennen?

/^((?:(?:[^?+*{}()[\]\\|]+|\\.|\[(?:\^?\\.|\^[^\\]|[^\\^])(?:[^\]\\]+|\\.)*\]|\((?:\?[:=!]|\?<[=!]|\?>)?(?1)??\)|\(\?(?:R|[+-]?\d+)\))(?:(?:[?+*]|\{\d+(?:,\d*)?\})[?+]?)?|\|)*)$/
evandentremont
quelle
Sicherlich kann das im allgemeinen Fall unmöglich funktionieren?
Mike Chamberlain
Diese Regex ist rekursiv. Es ist also keine Regex im klassischen Sinne des Wortes, aber es funktioniert in Perl Compatible Regular Expression-Engines.
Ptmalcolm
2

Ohne den regulären Ausdruck tatsächlich auszuführen, können Sie nicht sicher sein, ob er gültig ist. Ich habe kürzlich einen ähnlichen RegexValidator für Zend Framework implementiert. Funktioniert gut.

<?php
class Nuke_Validate_RegEx extends Zend_Validate_Abstract
{
    /**
     * Error constant
     */
    const ERROR_INVALID_REGEX = 'invalidRegex';

    /**
     * Error messages
     * @var array
     */
    protected $_messageTemplates = array(
        self::ERROR_INVALID_REGEX => "This is a regular expression PHP cannot parse.");

    /**
     * Runs the actual validation
     * @param string $pattern The regular expression we are testing
     * @return bool
     */
    public function isValid($pattern)
    {
        if (@preg_match($pattern, "Lorem ipsum") === false) {
            $this->_error(self::ERROR_INVALID_REGEX);
            return false;
        }
        return true;
    }
}
ChrisR
quelle
1

Sie können Ihren regulären Ausdruck mit einem regulären Ausdruck und bis zu einer bestimmten Grenze validieren . Überprüfen Sie diese Stapelüberlaufantwort für weitere Informationen.

Hinweis: Ein "rekursiver regulärer Ausdruck" ist kein regulärer Ausdruck, und diese erweiterte Version von Regex stimmt nicht mit erweiterten Regex überein.

Eine bessere Option ist es, preg_matchNULL zu verwenden und gegen NULL abzugleichen , wie @Claudrian sagte

Rajukoyilandy
quelle
1

Zusammenfassend können Sie für alle, die zu dieser Frage kommen, reguläre Ausdrücke in PHP mit einer Funktion wie dieser validieren.

preg_match () gibt 1 zurück, wenn das Muster mit dem angegebenen Betreff übereinstimmt, 0, wenn dies nicht der Fall ist, oder FALSE, wenn ein Fehler aufgetreten ist. - PHP-Handbuch

/**
 * Return an error message if the regular expression is invalid
 *
 * @param string $regex string to validate
 * @return string
 */
function invalidRegex($regex)
{
    if(preg_match($regex, null) !== false)
    {
        return '';
    }

    $errors = array(
        PREG_NO_ERROR               => 'Code 0 : No errors',
        PREG_INTERNAL_ERROR         => 'Code 1 : There was an internal PCRE error',
        PREG_BACKTRACK_LIMIT_ERROR  => 'Code 2 : Backtrack limit was exhausted',
        PREG_RECURSION_LIMIT_ERROR  => 'Code 3 : Recursion limit was exhausted',
        PREG_BAD_UTF8_ERROR         => 'Code 4 : The offset didn\'t correspond to the begin of a valid UTF-8 code point',
        PREG_BAD_UTF8_OFFSET_ERROR  => 'Code 5 : Malformed UTF-8 data',
    );

    return $errors[preg_last_error()];
}

Welches kann so verwendet werden.

if($error = invalidRegex('/foo//'))
{
    die($error);
}
Xeoncross
quelle
0

Ich würde gerne eine Reihe von Unit-Tests für Ihre Regex einrichten. Auf diese Weise können Sie nicht nur sicherstellen, dass der reguläre Ausdruck tatsächlich gültig ist, sondern auch beim Abgleichen wirksam.

Ich finde, die Verwendung von TDD ist ein effektiver Weg, um Regex zu entwickeln, und bedeutet, dass die zukünftige Erweiterung vereinfacht wird, da Sie bereits alle Ihre Testfälle zur Verfügung haben.

Die Antwort auf diese Frage bietet eine hervorragende Antwort zum Einrichten Ihrer Komponententests.

Rob Forrest
quelle
Danke Rob. Ich bin ein Fan von TDD, aber der betreffende Code muss in der Lage sein, Regex als Eingabe zu validieren (ich validiere JSON-Schemas, die Regex-Muster enthalten können).
Ross McFarlane
0

Sie sollten versuchen, den regulären Ausdruck mit abzugleichen NULL. Wenn das Ergebnis FALSE ( === FALSE) ist, ist ein Fehler aufgetreten.

In PHP> = 5.5 können Sie Folgendes verwenden, um die integrierte Fehlermeldung automatisch abzurufen, ohne Ihre eigene Funktion definieren zu müssen, um sie abzurufen:

preg_match($regex, NULL);
echo array_flip(get_defined_constants(true)['pcre'])[preg_last_error()];
mbomb007
quelle
-3

Laut der PCRE-Referenz gibt es keine Möglichkeit, die Gültigkeit eines Ausdrucks zu testen, bevor er verwendet wird. Aber ich denke, wenn jemand einen ungültigen Ausdruck verwendet, ist es ein Designfehler in dieser Anwendung, kein Laufzeitfehler, also sollte es Ihnen gut gehen.

pozs
quelle
-1, da die Frage des OP nicht vor seiner Verwendung, sondern vor der Verwendung gegen reale Daten gestellt wurde. Eine Sache ist das Testen mit 5 MB Scraped-Daten und eine andere mit einer leeren Zeichenfolge, die nur überprüft, ob RegExp kompiliert wird. SO: In PHP können Sie es testen, in C ++ können Sie es testen. In C ++ 11 wird eine Ausnahme ausgelöst, wenn sie ungültig ist. In PHP erhalten Sie die explizite falsche. RegExp wird vor seiner Ausführung kompiliert. Hier treten die Fehler auf, da die Kompilierung fehlschlägt, wenn es illegal ist, unabhängig davon, für welche Daten Sie es verwenden. Meine Güte ...
CodeAngry
@Claudrian: Ich stimme zu, aber die Frage war nicht bevor sie gegen reale Daten verwendet wurde , sondern vorzugsweise bevor sie verwendet wurde - und es gibt keine solche Möglichkeit (als explizite / dedizierte Funktion). Aber ich stimme zu, wenn man es wirklich testen möchte, sollte es gegen Null / Leerwert getestet werden.
pozs