Reguläre Ausdrücke müssen bekannt und verstanden sein – schauen Sie sich um

Inhaltsverzeichnis

1. Einführung in das Umsehen

2. Schauen Sie nach vorne

3. Schauen Sie nach hinten

4. Schauen Sie sich negativ um


1. Einführung in das Umsehen

        Schauen wir uns zunächst ein Beispiel an: Extrahieren des Seitentitels einer Webseite. Der HTML-Seitentitel ist der Text, der zwischen den Tags <title> und </title> erscheint. Diese Tags müssen sich im Abschnitt <head> des HTML-Codes befinden.

mysql> set @s:='<head>
    '> <title>Ben Forta\'s Homepage</title>
    '> </head>';
Query OK, 0 rows affected (0.00 sec)

mysql> set @r:='(?<=<head>[\\s]{0,10}<title>).*(?=</title>[\\s]{0,10}</head>)';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, 'n') c, regexp_extract(@s, @r, 'n') s, regexp_extract_index(@s, @r, 0, 'n') i;
+------+----------------------+------+
| c    | s                    | i    |
+------+----------------------+------+
|    1 | Ben Forta's Homepage | 15   |
+------+----------------------+------+
1 row in set (0.00 sec)

        (?<=<head>[\\s]{0,10}<title>) ist eine Look-Behind-Operation, die <title> abgleicht, aber nicht verbraucht; (?=</title>[\\s] { 0,10}</head>) ist eine Look-Ahead-Operation, die </title> abgleicht, aber nicht verbraucht. Die endgültige zurückgegebene Übereinstimmung enthält nur den Titeltext, der von dieser Regex nur verbraucht wird. Um Mehrdeutigkeiten zu reduzieren, sollte < in diesem Beispiel maskiert werden, d. h. (?<=< sollte durch (?<=\< ersetzt werden. MySQL-Rückwärtssuche für reguläre Ausdrücke unterstützt * nicht, unterstützt aber Intervallbereiche:

mysql> set @r:='(?<=<head>.*<title>).*(?=</title>.*</head>)';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, 'n') c, regexp_extract(@s, @r, 'n') s, regexp_extract_index(@s, @r, 0, 'n') i;
ERROR 3695 (HY000): The look-behind assertion exceeds the limit in regular expression.

mysql> set @r:='(?<=<head>.{0,}<title>).{0,}(?=</title>.*</head>)';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, 'n') c, regexp_extract(@s, @r, 'n') s, regexp_extract_index(@s, @r, 0, 'n') i;
ERROR 3695 (HY000): The look-behind assertion exceeds the limit in regular expression.

mysql> set @r:='(?<=<head>.{0,100}<title>).*(?=</title>.*</head>)';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, 'n') c, regexp_extract(@s, @r, 'n') s, regexp_extract_index(@s, @r, 0, 'n') i;
+------+----------------------+------+
| c    | s                    | i    |
+------+----------------------+------+
|    1 | Ben Forta's Homepage | 15   |
+------+----------------------+------+
1 row in set (0.00 sec)

2. Schauen Sie nach vorne

        Lookahead gibt ein Muster an, das abgeglichen werden muss, aber nicht im Ergebnis zurückgegeben werden darf. Look Ahead ist eigentlich ein Unterausdruck, und das gilt auch aus Formatsicht. Die Syntax für ein Lookahead-Muster ist ein Unterausdruck, der mit ?= beginnt, und der abzugleichende Text folgt auf =.

        In einigen Dokumentationen zu regulären Ausdrücken wird der Begriff „verbrauchen“ im Sinne von „Text abgleichen und zurückgeben“ verwendet. Freuen Sie sich auf den passenden Text mit „nicht konsumieren“. Schauen wir uns ein Beispiel an. Der folgende Text enthält eine Reihe von URL-Adressen. Die Aufgabe besteht darin, den Protokollteil jeder Adresse zu extrahieren.

mysql> set @s:='http://www.forta.com/ https://mail.forta.com/ ftp://ftp.forta.com/';
Query OK, 0 rows affected (0.00 sec)

mysql> set @r:='\\w+?(?=:)';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+----------------+---------+
| c    | s              | i       |
+------+----------------+---------+
|    3 | http,https,ftp | 1,23,47 |
+------+----------------+---------+
1 row in set (0.00 sec)

        In der oben aufgeführten URL-Adresse werden der Protokollname und der Hostname durch ein: getrennt. Das Muster \\w+? stimmt träge mit jedem Wort überein, und der Unterausdruck (?=:) stimmt mit: überein. Beachten Sie jedoch, dass „matched:“ nicht im endgültigen Matching-Ergebnis erscheint. ?= weist die Engine für reguläre Ausdrücke an: match:, nur nach vorne zu schauen, ohne dieses Zeichen zu verbrauchen. Um die Wirkung von ?= besser zu verstehen, schauen wir uns dasselbe Beispiel noch einmal an, diesmal jedoch ohne Verwendung des Lookahead-Metazeichens.

mysql> set @s:='http://www.forta.com/
    '> https://mail.forta.com/
    '> ftp://ftp.forta.com/';
Query OK, 0 rows affected (0.00 sec)

mysql> set @r:='\\w+?(:)';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+-------------------+---------+
| c    | s                 | i       |
+------+-------------------+---------+
|    3 | http:,https:,ftp: | 1,23,47 |
+------+-------------------+---------+
1 row in set (0.00 sec)

        Der Unterausdruck (:) stimmt korrekt mit dem Zeichen : überein und verbraucht es, das als Teil des endgültigen Übereinstimmungsergebnisses zurückgegeben wird. Der Unterschied zwischen diesen beiden Beispielen besteht darin, dass ersteres beim Matching: das Muster (?=:) verwendet, während letzteres das Muster (:) verwendet. Die beiden Muster stimmen mit demselben überein, nämlich mit dem : unmittelbar nach dem Protokollnamen. Der Unterschied besteht darin, ob das übereinstimmende : im endgültigen Übereinstimmungsergebnis erscheint. Bei Verwendung von Lookahead schaut der Regex-Parser voraus und verarbeitet die :-Übereinstimmung, bezieht sie jedoch nicht in das Endergebnis ein. Das Muster \w+?(:) findet Text, der : enthält, und das Muster \w+?(?=:) findet Text, der : nicht enthält.

        Beim Vorwärts- und Rückblicken werden tatsächlich Ergebnisse zurückgegeben, aber die Ergebnisse sind immer Zeichenfolgen der Länge Null. Daher werden Lookaround-Operationen manchmal als Nullbreiten-Matching-Operationen bezeichnet. Jeder Unterausdruck kann in einen Lookahead-Ausdruck umgewandelt werden, indem ihm ?= vorangestellt wird. Im selben Suchmuster können mehrere Lookahead-Ausdrücke verwendet werden, ohne Einschränkungen hinsichtlich der Position, an der sie angezeigt werden.

3. Schauen Sie nach hinten

        Wie Sie gerade gesehen haben, blickt ?= nach vorne und schaut auf das, was nach dem passenden Text kommt, verbraucht ihn aber nicht. Daher wird ?= als Lookahead-Operator bezeichnet. Viele Implementierungen regulärer Ausdrücke unterstützen nicht nur das Vorwärtsschauen, sondern auch das Rückwärtsschauen, also das Betrachten von Inhalten, die vor dem übereinstimmenden Text erscheinen. Der rückwärtsblickende Operator ist ?<=.

        Eine Möglichkeit, ?= von ?<= zu unterscheiden: Operatoren, die Pfeile (<-Symbole) enthalten, die nach hinten im Text zeigen, blicken nach hinten. Da die Richtung des Textes relativ zum Muster (entsprechend der „Vorderseite“ von „nach vorne schauen“) der Leserichtung des Textes entgegengesetzt ist, kann es leicht zu Missverständnissen kommen, wenn man sich beim Rückblicken an die Richtung des <-Zeichens erinnert kann „?<=“ direkt lesen, um „sich um … zu kümmern“. ?<= wird auf die gleiche Weise wie ?= verwendet, es muss in einem Unterausdruck erscheinen, gefolgt vom zu vergleichenden Text. Unten finden Sie ein Beispiel. Es wird eine Produktliste aus einer bestimmten Datenbank durchsucht, es wird jedoch nur der Produktpreis benötigt.

mysql> set @s:='ABC01: $23.45
    '> HGG42: $5.31
    '> CFMX1: $899.00
    '> XTC99: $69.96
    '> Total items found: 4';
Query OK, 0 rows affected (0.00 sec)

mysql> set @r:='\\$[0-9.]+';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+-----------------------------+------------+
| c    | s                           | i          |
+------+-----------------------------+------------+
|    4 | $23.45,$5.31,$899.00,$69.96 | 8,22,35,50 |
+------+-----------------------------+------------+
1 row in set (0.00 sec)

        \$ entspricht dem $-Zeichen, [0-9.]+ entspricht dem Preis und das Übereinstimmungsergebnis ist korrekt. Was aber, wenn Sie nicht möchten, dass das Zeichen „$“ im Endergebnis der Übereinstimmung erscheint?

mysql> set @r:='(?<=\\$)[0-9.]+';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+-------------------------+------------+
| c    | s                       | i          |
+------+-------------------------+------------+
|    4 | 23.45,5.31,899.00,69.96 | 9,23,36,51 |
+------+-------------------------+------------+
1 row in set (0.00 sec)

        Das Problem ist behoben. (?<=\$) entspricht dem $-Zeichen, verbraucht es jedoch nicht. Das endgültige Übereinstimmungsergebnis enthält nur die Preisnummer. Vergleichen Sie die beiden Ausdrücke in diesem Beispiel: \$[0-9.]+ entspricht einem $-Zeichen und einem Dollarbetrag; (?<=\$)[0-9.]+ entspricht auch einem $-Zeichen und einem Dollarbetrag . Diese beiden Muster suchen nach dem Gleichen und der Unterschied zwischen ihnen spiegelt sich im endgültigen Matching-Ergebnis wider. Die Übereinstimmung des ersteren enthält das Zeichen „$“, die Übereinstimmung des letzteren enthält das Zeichen „$“ nicht, obwohl sie mit dem Zeichen „$“ übereinstimmen muss, um diese Preiszahlen korrekt zu finden.

        Das Lookahead-Muster hat eine variable Länge und kann Quantoren wie . und + enthalten, sodass es sehr flexibel ist. Der Rückblickmodus kann nur eine feste Länge haben. Fast alle Implementierungen regulärer Ausdrücke weisen diese Einschränkung auf.

4. Schauen Sie sich negativ um

        Bisher wurden „Vorwärtsblick“ und „Rückblick“ im Allgemeinen zum Abgleichen von Text verwendet, hauptsächlich um die Position des als Treffer zurückgegebenen Textes anzugeben (wodurch der Text vor oder nach dem gewünschten Treffer angegeben wird). Diese Verwendung wird als positiver Lookahead und positiver Lookbehind bezeichnet. Der Begriff „positiv“ bezieht sich auf einen durchgeführten Matching-Vorgang. Es gibt auch eine weniger verbreitete Form des Lookarounds, die als negativer Lookaround bezeichnet wird. Ein negativer Lookahead sucht vorwärts nach Text, der nicht mit dem angegebenen Muster übereinstimmt, und ein negativer Lookbehind sucht rückwärts nach Text, der nicht dem angegebenen Muster entspricht. Um den Lookaround-Vorgang zu negieren, verwenden Sie ! anstelle von =. In der folgenden Tabelle sind alle Suchvorgänge aufgeführt.

Typ

veranschaulichen

(?=)

Ich freue mich auf jeden Fall

(?!)

negativer Ausblick

(?<=)

Schauen Sie auf jeden Fall nach hinten

(?<!)

negative Suche

        Im Allgemeinen unterstützt jede reguläre Ausdrucksimplementierung, die Lookahead unterstützt, auch positives Lookahead und negatives Lookahead. Ebenso unterstützt jede reguläre Ausdrucksimplementierung, die Lookback unterstützt, auch positives Lookbehind und negatives Lookbehind. Schauen wir uns ein Beispiel an. Unten finden Sie einen Text mit Werten, der sowohl Preis als auch Menge enthält. Lassen Sie uns zuerst den Preis ermitteln.

mysql> set @s:='I paid $30 for 100 apples,
    '> 50 oranges, and 60 pears.
    '> I saved $5 on this order.';
Query OK, 0 rows affected (0.00 sec)

mysql> set @r:='(?<=\\$)\\d+';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+------+------+
| c    | s    | i    |
+------+------+------+
|    2 | 30,5 | 9,63 |
+------+------+------+
1 row in set (0.00 sec)

        Dies ähnelt dem vorherigen Beispiel. \d+ stimmt mit numerischen Werten überein, (?<=\$) sucht dahinter, ohne $-Zeichen zu verbrauchen (in Mustern als \$ maskiert). Dieses Muster stimmte korrekt mit den beiden zur Darstellung des Preises verwendeten Werten überein, und die zur Darstellung der Menge verwendeten Zahlen erschienen nicht im endgültigen Übereinstimmungsergebnis. Machen Sie es nun umgekehrt und schauen Sie nur nach der Menge, nicht nach dem Preis.

mysql> set @r:='\\b(?<!\\$)\\d+\\b';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+-----------+----------+
| c    | s         | i        |
+------+-----------+----------+
|    3 | 100,50,60 | 16,28,44 |
+------+-----------+----------+
1 row in set (0.00 sec)

        \d+ stimmt erneut mit dem Wert überein, dieses Mal jedoch nur mit der Menge, nicht mit dem Preis. Der Ausdruck (?<!\$) ist ein negierter Lookbehind, der nur dann zutrifft, wenn das Zeichen vor der Zahl nicht $ ist. Durch Ändern des = im Lookbehind-Operator in ! ändert sich der Modus von positivem Lookbehind zu negativem Lookbehind. Warum wird \b im obigen Muster auch verwendet, um eine Wortgrenze anzugeben? Sehen Sie sich das Beispiel unten an, in dem keine Wortgrenzen verwendet werden, um zu sehen, warum.

mysql> set @r:='(?<!\\$)\\d+';
Query OK, 0 rows affected (0.00 sec)

mysql> select regexp_count(@s, @r, '') c, regexp_extract(@s, @r, '') s, regexp_extract_index(@s, @r, 0, '') i;
+------+-------------+-------------+
| c    | s           | i           |
+------+-------------+-------------+
|    4 | 0,100,50,60 | 10,16,28,44 |
+------+-------------+-------------+
1 row in set (0.00 sec)

        Da keine Wortgrenzen verwendet werden, erscheint die 0 in $30 auch im endgültigen Matching-Ergebnis. Dies liegt daran, dass das Zeichen vor diesem Zeichen 0 3 und nicht das Zeichen $ ist, was die Übereinstimmungsanforderungen des Musters (?<!\$)\d+ vollständig erfüllt. Dieses Problem wird gelöst, indem das gesamte Muster in Wortgrenzen eingefügt wird.

        Lookarounds ermöglichen eine genauere Kontrolle darüber, was zurückgegeben wird. Mit der Look-Around-Operation können Sie Unterausdrücke verwenden, um anzugeben, wo die Textabgleichsoperation stattfindet. Gleichzeitig wird der abgeglichene Text jedoch nicht verbraucht (er erscheint nicht im endgültigen Abgleichsergebnis). Positive Lookaheads werden mit (?=) und negative Lookaheads mit (?!) definiert. Einige Implementierungen regulärer Ausdrücke unterstützen auch positives Lookbehind (der entsprechende Operator ist (?<=)) und negatives Lookbehind (der entsprechende Operator ist (?<!)).

Ich denke du magst

Origin blog.csdn.net/wzy0623/article/details/130984095
Empfohlen
Rangfolge