So extrahieren Sie einen optionalen Abfrageparameter mit regex in Javascript

8

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?

    
Misha Moroshko 15.09.2014, 11:24
quelle

10 Antworten

17

Die Antwort

Screw Ihre harte Arbeit, ich will nur die Antwort! Okay, hier gehst du ...

%Vor% %Vor%

Forschung

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:

  1. Ihre Beispiele beginnen mit dem Pfad, daher beginnt der Pfad vom Anfang der Zeichenfolge bis zu ? (Abfragezeichenfolge), # (Anker) oder dem Ende der Zeichenfolge.
  2. Die Query-Zeichenfolge ist der ify-Teil, da RFC keine "Norm" definiert. Ein Browser erwartet, dass eine Abfragezeichenfolge aus einer Formularübergabe generiert wird und eine Liste von key=value -Paaren ist, die von & -Zeichen angehängt werden. Behalte diese Mentalität:
    • Ein Schlüssel darf nicht null sein, ihm wird ein ? oder & vorangestellt, und er darf kein = , & oder # .
    • enthalten
    • Ein Wert ist optional, ihm wird key= vorangestellt, und er darf keine & oder # enthalten.
  3. Alles nach einem # -Zeichen ist der Anker.

Fangen wir an!

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.

%Vor%

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.

%Vor%

Hören Sie auf, sich zu bewegen

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:

%Vor%

Hier einige wichtige Dinge:

  • Javascript unterstützt keine Lookbehinds, das heißt, Sie können nicht nach einem ? 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.
  • Der Abfrage-String wiederholt nun jeweils ein Zeichen in einer nicht-einfangenden Gruppe..wenn er den Schlüssel foo nicht sieht, in diesem Fall erfasst er den optionalen Wert und fährt mit der Wiederholung fort.
  • Da diese Nicht-Capture-Abfrage-String-Gruppe den ganzen Weg bis zum Anker oder Ende des URI wiederholt, würde ein zweiter foo-Wert ( 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.

Endgültige Lösung?

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 .

%Vor%

Schauen wir uns einige der juju genauer an, die in diesen Ausdruck eingeflossen sind:

  • Nachdem wir foo=\d* gefunden haben, verwenden wir einen Lookahead, um sicherzustellen, dass ein & , # oder das Ende der Zeichenfolge (das Ende eines Abfragezeichenfolgenwerts) folgt.
  • Allerdings..wenn es mehr zu 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.
  • Dies funktioniert mit mehreren 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.

    
Sam 19.09.2014, 06:15
quelle
5

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

%Vor%

    
Steve Chambers 19.09.2014 22:57
quelle
4
%Vor%

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=

überein

Das OP hat diese Anforderungen nicht erwähnt, und da er eine einfache Regex (Oxymoron?) will, habe ich nicht versucht, sie zu lösen.

    
Shannon Poole 23.09.2014 21:59
quelle
2
%Vor%

Sie können dies versuchen. Siehe Demo.

Ссылка

    
vks 15.09.2014 11:36
quelle
2

Sie können die folgende Regex versuchen:

%Vor%

regex101-Demo

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.

%Vor%     
Jerry 19.09.2014 06:05
quelle
1

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:

%Vor%

Ein Beispiel für regex101: Ссылка

    
hjpotter92 15.09.2014 11:49
quelle
1

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:

%Vor%

Oder eine Live-Demo für weitere Details

    
revo 22.09.2014 09:19
quelle
1
%Vor%

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:

  1. der ursprüngliche Pfad
  2. ein Fragezeichen (oder überspringen bis zum Ende)
  3. einige Blöcke, die durch Und-Zeichen beendet werden
  4. unsere Parametrierung
  5. eine abschließende Bestätigung, entweder das nächste syntaktische Element starten oder die Zeile
  6. beenden

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 '.

    
Jon Jay Obermark 25.09.2014 16:36
quelle
0

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"

Demo

  • ^(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
alpha bravo 26.09.2014 00:06
quelle
-1
%Vor%

regex /\b(foo|path)\=\d+\b/

    
Man Programmer 15.09.2014 11:29
quelle

Tags und Links