Ich möchte eine Regex konstruieren, die nach einem "Pfad" und einem "foo" -Parameter (nicht negative Ganzzahl) sucht. "foo" ist optional. Es sollte:
MATCH
%Vor%Passen Sie nicht auf
%Vor% Außerdem möchte ich den Wert von foo
erhalten, ohne eine zusätzliche Übereinstimmung zu erzielen.
Was wäre die einfachste Regex, um dies zu erreichen?
Screw Ihre harte Arbeit, ich will nur die Antwort! Okay, hier gehst du ...
Ihre Bounty-Anfrage fragt nach "glaubwürdigen und / oder offiziellen Quellen", also zitiere ich die RFC-Abfrage Zeichenfolgen .
Die Abfragekomponente enthält nicht hierarchische Daten, die zusammen mit Daten in der Pfadkomponente (Abschnitt 3.3) dazu dienen, eine Ressource im Rahmen des URI-Schemas und der Namensberechtigung (falls vorhanden) zu identifizieren. Die Abfragekomponente wird durch das erste Fragezeichen ("?") Angezeigt und durch ein Nummernzeichen ("#") oder durch das Ende des URI beendet.
Dies scheint absichtlich ziemlich vage zu sein: Ein Abfrage-String beginnt mit dem ersten ?
und wird mit einem #
(Beginn des Ankers) oder dem Ende des URI (oder in unserem Fall String / Zeile) beendet. Sie fahren fort zu erwähnen, dass die meisten Datensätze in key=value
pairs sind, was das ist, was Sie erwarten zu parsen (nehmen wir also an, dass der Fall ist ).
Da jedoch Abfragekomponenten häufig verwendet werden, um identifizierende Informationen in Form von "Schlüssel = Wert" -Paaren zu tragen, und ein häufig verwendeter Wert eine Referenz auf einen anderen URI ist, ist es manchmal besser für die Benutzerfreundlichkeit, eine prozentuale Codierung dieser Zeichen zu vermeiden .
In diesem Sinne nehmen wir ein paar Dinge über Ihre URIs an:
?
(Abfragezeichenfolge), #
(Anker) oder dem Ende der Zeichenfolge. key=value
-Paaren ist, die von &
-Zeichen angehängt werden. Behalte diese Mentalität:
null
sein, ihm wird ein ?
oder &
vorangestellt, und er darf kein =
, &
oder #
. key=
vorangestellt, und er darf keine &
oder #
enthalten. #
-Zeichen ist der Anker. Beginnen wir mit der Abbildung unserer grundlegenden URI-Struktur . Sie haben einen Pfad, bei dem es sich um Zeichen handelt, die bei der Zeichenfolge beginnen und bis zu ?
, #
oder am Ende der Zeichenfolge stehen. Sie haben eine optionale Abfragezeichenfolge, die bei ?
beginnt und bis zu #
oder dem Ende der Zeichenfolge reicht. Und Sie haben einen optionalen Anker, der bei #
beginnt und bis zum Ende der Zeichenfolge geht.
Lassen Sie etwas aufräumen , bevor Sie die Abfragezeichenfolge durchsuchen. Sie können den Pfad einfach so festlegen, dass er einem bestimmten Wert entspricht, indem Sie die erste Erfassungsgruppe ersetzen. Was immer Sie mit ( path
) ersetzen, muss gefolgt von einer optionalen Abfragezeichenfolge, einem optionalen Anker und dem Ende der Zeichenfolge (nicht mehr und nicht weniger) folgen. Da Sie den Anker nicht analysieren müssen, kann die Erfassungsgruppe ersetzt werden, indem Sie die Übereinstimmung entweder in #
oder am Ende der Zeichenfolge (am Ende des Abfrageparameters) beenden.
Okay, ich habe viel Setup gemacht, ohne mir wirklich Gedanken um Ihr konkretes Beispiel zu machen. Das nächste Beispiel entspricht einem bestimmten Pfad ( path
) und kann bei der Erfassung des Werts eines Parameters foo
optional einer Abfragezeichenfolge entsprechen. Dies bedeutet, dass Sie hier anhalten und nach einer gültigen Übereinstimmung suchen können. Wenn die Übereinstimmung gültig ist, muss die erste Erfassungsgruppe null
oder eine nicht negative ganze Zahl sein. Aber das war nicht deine Frage, oder? Das wurde viel komplizierter , deshalb werde ich den Ausdruck inline erklären:
Hier einige wichtige Dinge:
?
oder &
vor dem Schlüssel foo
suchen, was bedeutet, dass Sie tatsächlich eines dieser Zeichen abgleichen müssen, was den Beginn Ihrer Abfrage bedeutet string (die nach einem ?
sucht) muss ein Lookahead sein, damit Sie nicht wirklich mit ?
übereinstimmen. Dies bedeutet auch, dass Ihre Abfragezeichenfolge immer mindestens ein Zeichen ( ?
) enthält. Daher möchten Sie die Abfragezeichenfolge [^#]
1+ mal wiederholen. foo
nicht sieht, in diesem Fall erfasst er den optionalen Wert und fährt mit der Wiederholung fort. path?foo=123&foo=bar
) den initialen erfassten Wert überschreiben..dies wäre nicht 100% ig möglich sich auf die obige Lösung verlassen. Okay..nun, da ich den foo
-Wert erfasst habe, ist es Zeit, um das Match auf Werte zu beenden, die es nicht sind positive ganze Zahlen .
Schauen wir uns einige der juju genauer an, die in diesen Ausdruck eingeflossen sind:
foo=\d*
gefunden haben, verwenden wir einen Lookahead, um sicherzustellen, dass ein &
, #
oder das Ende der Zeichenfolge (das Ende eines Abfragezeichenfolgenwerts) folgt. foo=\d*
gibt, wird die Regex vom Alternator auf ein generisches [^#]
Match-Recht am [?&]
vor foo
zurückgesetzt. Das ist nicht gut, denn es wird weiterhin passen! Bevor Sie also nach einer generischen Abfragezeichenfolge suchen ( [^#]
), müssen Sie sicherstellen, dass Sie nicht auf foo
schauen (das muss von der ersten Änderung behandelt werden). Hier kommt das negative Lookahead (?![?&]foo=)
zum Tragen. foo
-Schlüsseln, da sie alle gleiche nicht negative ganze Zahlen haben müssen. Dadurch kann foo
optional sein (oder gleich null
). Haftungsausschluss: Die meisten Regex101-Demos verwenden PHP für eine bessere Syntaxhervorhebung und enthalten \n
in negativen Zeichenklassen, da es mehrere Zeilen mit Beispielen gibt.
Nette Frage! Scheint zuerst ziemlich einfach ... aber es gibt eine Menge von gotchas. Wäre es ratsam, eine beanspruchte Lösung zu überprüfen, wird Folgendes gehandhabt:
ZUSÄTZLICHE SPIELTESTS
%Vor%ZUSÄTZLICH NICHT MIT TESTS
%Vor%Der einfachste Regex, den ich für all diese zusätzlichen Fälle verwenden kann, ist:
%Vor% Es wird jedoch empfohlen, ?:
zu den nicht verwendeten Erfassungsgruppen hinzuzufügen, damit sie ignoriert werden, und Sie können den foo
-Wert aus Gruppe 1 einfach abrufen - siehe Debuggex-Demo
Im Grunde habe ich es nur in drei Teile zerlegt
%Vor%Siehe Validierung hier Ссылка
Vorbehalte:
entspricht path#bar=1&foo=27
stimmt nicht mit path?foo=
Das OP hat diese Anforderungen nicht erwähnt, und da er eine einfache Regex (Oxymoron?) will, habe ich nicht versucht, sie zu lösen.
Sie können die folgende Regex versuchen:
%Vor% Es gibt zwei mögliche Übereinstimmungen nach path
:
.*?foo=(\d+)\b
, d. h. foo
gefolgt von Ziffern.
ODER
()(?!.*foo)
eine leere Zeichenfolge, wenn keine foo
ahead vorhanden ist.
Fügen Sie einige Wortgrenzen hinzu ( \b
), wenn Sie nicht möchten, dass die Regex andere Wörter (z. B. einen anderen Parameter namens barfoobar
) um das foo
s interpretiert.
Sie können prüfen, ob 3 rd -Gruppen vorhanden sind. Es ist nicht dort, der foo
-Wert wäre null
; Ansonsten ist es die Gruppe selbst:
Ein Beispiel für regex101: Ссылка
Der Umgang mit Javascript-Engine, um Regular Expressions neben all den Mängeln zu machen, die es im Vergleich mit PCRE hat, ist irgendwie erfreulich!
Ich habe diese RegEx, einfach und verständlich gemacht:
%Vor%Erläuterungen
%Vor%Ausführbares Snippet:
Oder eine Live-Demo für weitere Details
Dies ist so kurz wie die meisten und liest sich einfacher, da Dinge, die einmal in der Zeichenkette vorkommen, einmal im RE erscheinen.
Wir stimmen überein:
Leider passt foo zu None anstatt zu "", wenn der foo-Parameter weggelassen wird, aber in Python (meiner Sprache der Wahl) wird das als angemessener erachtet. Sie können sich beschweren, wenn Sie möchten, oder einfach nur oder mit '.
Basierend auf den OP-Daten hier ist mein Versuchsmuster
%Vor% wenn Pfad gefunden wird: Untermuster # 1 enthält "Pfad"
Wenn foo gültig ist: Untermuster # 2 enthält "foo value if any"
^(path)\b
"Pfad" (?:[^f]+|f(?!oo=))
gefolgt von allem außer "foo=" (?!\bfoo=(?!\d+\b))
wenn "foo=" gefunden wird, darf es nichts anderes als \d+\b
sehen
(?:\bfoo=(\d+)\b)?
wenn valide "foo=" gefunden wird, erfasse "foo" value Tags und Links javascript regex