165 Stimmen

Wie kann ich mehrere Vorkommen mit einer Regex in JavaScript abgleichen, ähnlich wie bei PHP's preg_match_all()?

Ich versuche, url-codierte Zeichenfolgen zu analysieren, die aus Schlüssel=Wert-Paaren bestehen, die entweder durch & o & .

Im Folgenden wird nur das erste Vorkommen abgeglichen, wobei die Schlüssel und Werte in separate Ergebniselemente aufgeteilt werden:

var result = mystring.match(/(?:&|&)?([^=]+)=([^&]+)/)

Die Ergebnisse für die Zeichenfolge '1111342=Adam%20Franco&348572=Bob%20Jones' wären:

['1111342', 'Adam%20Franco']

Mit dem globalen Flag 'g' werden alle Vorkommen abgeglichen, aber nur die vollständig übereinstimmenden Teilstrings zurückgegeben, nicht die getrennten Schlüssel und Werte:

var result = mystring.match(/(?:&|&)?([^=]+)=([^&]+)/g)

Die Ergebnisse für die Zeichenfolge '1111342=Adam%20Franco&348572=Bob%20Jones' wären:

['1111342=Adam%20Franco', '&348572=Bob%20Jones']

Während ich die Zeichenkette aufteilen könnte & und jedes Schlüssel/Wert-Paar einzeln aufschlüsseln, gibt es eine Möglichkeit, mit der JavaScript-Unterstützung für reguläre Ausdrücke auf mehrere Vorkommen des Musters /(?:&|&)?([^=]+)=([^&]+)/ ähnlich wie PHPs preg_match_all() Funktion?

Ich suche nach einer Möglichkeit, Ergebnisse zu erhalten, bei denen die Unterübereinstimmungen getrennt sind:

[['1111342', '348572'], ['Adam%20Franco', 'Bob%20Jones']]

o

[['1111342', 'Adam%20Franco'], ['348572', 'Bob%20Jones']]

9 Stimmen

Es ist ein wenig seltsam, dass niemand die Verwendung von replace hier. var data = {}; mystring.replace(/(?:&|&)?([^=]+)=([^&]+)/g, function(a,b,c,d) { data[c] = d; }); erledigt. "matchAll" in JavaScript ist "replace" mit einer Ersetzungsfunktion anstelle einer Zeichenkette.

0 Stimmen

Für diejenigen, die diese Frage im Jahr 2020 immer noch nicht beantworten können, lautet die Antwort: "Don't use regex, use URLSearchParams die all dies für Sie erledigt."

170voto

Tomalak Punkte 320467

Aus den Kommentaren entnommen

Anmerkung 2020: Anstatt Regex zu verwenden, haben wir jetzt URLSearchParams die all dies für uns erledigt, so dass kein benutzerdefinierter Code, geschweige denn Regex, mehr erforderlich ist.

- Mike 'Pomax' Kamermans

Die Browserunterstützung ist hier aufgelistet https://caniuse.com/#feat=urlsearchparams


Ich würde eine alternative Regex vorschlagen, die Untergruppen verwendet, um Name und Wert der Parameter einzeln zu erfassen und re.exec() :

function getUrlParams(url) {
  var re = /(?:\?|&(?:amp;)?)([^=&#]+)(?:=?([^&#]*))/g,
      match, params = {},
      decode = function (s) {return decodeURIComponent(s.replace(/\+/g, " "));};

  if (typeof url == "undefined") url = document.location.href;

  while (match = re.exec(url)) {
    params[decode(match[1])] = decode(match[2]);
  }
  return params;
}

var result = getUrlParams("http://maps.google.de/maps?f=q&source=s_q&hl=de&geocode=&q=Frankfurt+am+Main&sll=50.106047,8.679886&sspn=0.370369,0.833588&ie=UTF8&ll=50.116616,8.680573&spn=0.35972,0.833588&z=11&iwloc=addr");

result ist ein Objekt:

{
  f: "q"
  geocode: ""
  hl: "de"
  ie: "UTF8"
  iwloc: "addr"
  ll: "50.116616,8.680573"
  q: "Frankfurt am Main"
  sll: "50.106047,8.679886"
  source: "s\_q"
  spn: "0.35972,0.833588"
  sspn: "0.370369,0.833588"
  z: "11"
}

Die Regex setzt sich wie folgt zusammen:

(?:            # non-capturing group
  \\?|&         #   "?" or "&"
  (?:amp;)?    #   (allow "&", for wrongly HTML-encoded URLs)
)              # end non-capturing group
(              # group 1
  \[^=&#\]+      #   any character except "=", "&" or "#"; at least once
)              # end group 1 - this will be the parameter's name
(?:            # non-capturing group
  =?           #   an "=", optional
  (            #   group 2
    \[^&#\]\*     #     any character except "&" or "#"; any number of times
  )            #   end group 2 - this will be the parameter's value
)              # end non-capturing group

24 Stimmen

Genau das hatte ich mir erhofft. Was ich noch nie in der JavaScript-Dokumentation gesehen habe, ist der Hinweis, dass die exec()-Methode weiterhin die nächste Ergebnismenge zurückgibt, wenn sie mehr als einmal aufgerufen wird. Nochmals vielen Dank für den tollen Tipp!

1 Stimmen

Das ist der Grund dafür: reguläre-ausdrücke.info/javascript.html (Lesen Sie dazu: "Wie man das JavaScript RegExp-Objekt verwendet")

1 Stimmen

Es gibt einen Fehler in diesem Code: das Semikolon nach dem "while" sollte entfernt werden.

68voto

meouw Punkte 40856

Für eine globale Suche müssen Sie den Schalter 'g' verwenden

var result = mystring.match(/(&|&)?([^=]+)=([^&]+)/g)

36 Stimmen

Dies löst das Problem nicht wirklich: "Die Verwendung des globalen Flags 'g' führt zu einer Übereinstimmung mit allen Vorkommen, gibt aber nur die vollständig übereinstimmenden Teilstrings zurück, nicht die getrennten Schlüssel und Werte."

40voto

2020 bearbeiten

Utilice URLSearchParams da für diese Aufgabe kein eigener Code mehr erforderlich ist. Die Browser können dies mit einem einzigen Konstruktor für Sie erledigen:

const str = "1111342=Adam%20Franco&348572=Bob%20Jones";
const data = new URLSearchParams(str);
for (pair of data) console.log(pair)

ergibt

Array [ "1111342", "Adam Franco" ]
Array [ "348572", "Bob Jones" ]

Es gibt also keinen Grund mehr, dafür Regex zu verwenden.

Ursprüngliche Antwort

Wenn Sie sich nicht auf den "blinden Abgleich" verlassen wollen, der mit der Ausführung von exec Stil-Matching, JavaScript kommt mit Match-All-Funktionalität eingebaut, aber es ist Teil der replace Funktionsaufruf, wenn ein "Was tun mit den Erfassungsgruppen" verwendet wird Bearbeitungsfunktion :

var data = {};

var getKeyValue = function(fullPattern, group1, group2, group3) {
  data[group2] = group3;
};

mystring.replace(/(?:&|&)?([^=]+)=([^&]+)/g, getKeyValue);

erledigt.

Anstatt die Funktion zur Behandlung von Erfassungsgruppen zu verwenden, um tatsächlich Ersetzungszeichenfolgen zurückzugeben (bei der Ersetzungsbehandlung ist das erste Argument die vollständige Musterübereinstimmung, und die nachfolgenden Argumente sind einzelne Erfassungsgruppen), nehmen wir einfach die Erfassungen der Gruppen 2 und 3 und zwischenspeichern dieses Paar.

Anstatt also komplizierte Parsing-Funktionen zu schreiben, sollten Sie sich daran erinnern, dass die Funktion "matchAll" in JavaScript einfach "replace" mit einer Ersetzungsfunktion ist, und dass die Mustererkennung sehr effizient ist.

0 Stimmen

Ich habe eine Zeichenfolge something "this one" and "that one" . Ich möchte alle in Anführungszeichen gesetzten Zeichenfolgen in einer Liste zusammenfassen, z. B. [diese, jene]. So weit mystring.match(/"(.*?)"/) funktioniert gut bei der Erkennung der ersten, aber ich weiß nicht, wie ich Ihre Lösung für eine einzelne Erfassungsgruppe anpassen kann.

2 Stimmen

Klingt so, als ob Sie dafür eine Frage auf Stackoverflow stellen sollten, anstatt zu versuchen, das Problem in den Kommentaren zu lösen.

0 Stimmen

Ich habe eine neue Frage erstellt: stackoverflow.com/questions/26174122/

21voto

Aram Kocharyan Punkte 19721

Für die Erfassung von Gruppen verwende ich gewöhnlich preg_match_all in PHP und ich habe versucht, seine Funktionalität hier zu replizieren:

<script>

// Return all pattern matches with captured groups
RegExp.prototype.execAll = function(string) {
    var match = null;
    var matches = new Array();
    while (match = this.exec(string)) {
        var matchArray = [];
        for (i in match) {
            if (parseInt(i) == i) {
                matchArray.push(match[i]);
            }
        }
        matches.push(matchArray);
    }
    return matches;
}

// Example
var someTxt = 'abc123 def456 ghi890';
var results = /[a-z]+(\d+)/g.execAll(someTxt);

// Output
[["abc123", "123"],
 ["def456", "456"],
 ["ghi890", "890"]]

</script>

4 Stimmen

@teh_senaus müssen Sie den globalen Modifikator mit /g sonst läuft exec() ändert den aktuellen Index nicht und bildet eine Endlosschleife.

0 Stimmen

Wenn ich diesen Code myRe.test(str) aufrufe, um ihn zu validieren, und dann versuche, execAll auszuführen, startet er bei der zweiten Übereinstimmung und wir haben die erste Übereinstimmung verloren.

0 Stimmen

@fdrv Sie müssen den lastIndex auf Null zurücksetzen, bevor Sie die Schleife starten: this.lastIndex = 0;

14voto

Gumbo Punkte 617646

Stellen Sie die g Modifikator für eine globale Übereinstimmung:

/…/g

13 Stimmen

Dies löst das Problem nicht wirklich: "Die Verwendung des globalen Flags 'g' führt zu einer Übereinstimmung mit allen Vorkommen, gibt aber nur die vollständig übereinstimmenden Teilstrings zurück, nicht die getrennten Schlüssel und Werte."

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