webentwicklung-frage-antwort-db.com.de

Wie kann ich mehrere Vorkommen mit einem Regex in JavaScript vergleichen, der dem PHP preg_match_all () ähnelt?

Ich versuche, url-codierte Zeichenfolgen zu analysieren, die aus Schlüssel/Wert-Paaren bestehen, die durch & oder & getrennt sind. 

Folgendes trifft nur auf das erste Vorkommen zu und teilt die Schlüssel und Werte in separate Ergebniselemente auf:

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

Die Ergebnisse für die Zeichenfolge "1111342 = Adam% 20Franco & 348572 = Bob% 20Jones" lauten:

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

Wenn Sie das globale Flag "g" verwenden, werden alle Vorkommen abgeglichen, es werden jedoch nur die vollständig übereinstimmenden Teilzeichenfolgen 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" lauten:

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

Während ich die Zeichenfolge in & aufteilen und jedes Schlüssel/Wert-Paar einzeln aufteilen könnte, gibt es eine Möglichkeit, die Unterstützung für reguläre Ausdrücke von JavaScript zu verwenden, um mehrere Vorkommen des Musters /(?:&|&)?([^=]+)=([^&]+)/ ähnlich der PHP-Funktion preg_match_all() zu finden?

Ich strebe nach einer Möglichkeit, Ergebnisse zu erzielen, bei denen die Sub-Matches getrennt sind:

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

oder 

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

Ich würde einen alternativen Regex vorschlagen, der Untergruppen verwendet, um Namen und Wert der Parameter einzeln zu erfassen:

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" 
 dh: "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" 
} 

Der reguläre Ausdruck gliedert sich folgendermaßen:

 (?: # Gruppe, die keine Capturing-Gruppe enthält 
 \? | & # "?" oder "&" 
 (?: amp;)? # (Erlaube "& amp;" für falsch HTML-kodierte URLs ) 
) # Ende nicht erfassende Gruppe 
 (# Gruppe 1 
 [^ = & #] + # beliebiges Zeichen außer "=", "&" oder "#"; ) # end group 1 - Dies ist der Name des Parameters 
 (?: # nicht erfassende Gruppe 
 =? # an "=", optional 
 (# group 2 
 [^ & #] * # beliebiges Zeichen außer "&" oder "#"; beliebig oft 
) # end Gruppe 2 - Dies ist der Wert des Parameters 
) # end nicht erfassende Gruppe 
153
Tomalak

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

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

Wenn Sie sich nicht auf das "Blind-Matching" verlassen möchten, das mit dem Abgleich von exec / style geliefert wird, ist in JavaScript eine Match-All-Funktion eingebaut, die jedoch zum Funktionsaufruf replace gehört. bei Verwendung einer "Was tun mit Capture-Gruppen" Handling-Funktion :

var data = {};

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

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

erledigt.

Anstatt die Erfassungsgruppenbehandlungsfunktion tatsächlich zum Ersetzen von Ersetzungszeichenfolgen zu verwenden, ist das erste Argument, a, hier die vollständige Musterübereinstimmung, und die nachfolgenden Argumente sind einzelne Erfassungsgruppen. In diesem Fall ist b Gruppe 1, c group 2 usw.) Wir nehmen einfach die Captures der Gruppen 2 und 3 und zwischenspeichern dieses Paar.

Vergessen Sie nicht, komplizierte Parsing-Funktionen zu schreiben, denken Sie daran, dass die Funktion "matchAll" in JavaScript einfach durch eine Ersetzungshandler-Funktion "ersetzt" wird, und dass Sie eine sehr gute Pattern-Matching-Effizienz erzielen können.

Zum Erfassen von Gruppen bin ich es gewohnt, preg_match_all in PHP zu verwenden, und ich habe versucht, die 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>
21
Aram Kocharyan

Legen Sie den Modifizierer g für eine globale Übereinstimmung fest:

/…/g
15
Gumbo

Quelle: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec

Suche nach aufeinanderfolgenden Übereinstimmungen

Wenn Ihr regulärer Ausdruck das Flag "g" verwendet, können Sie die Methode exec () mehrmals verwenden, um aufeinanderfolgende Übereinstimmungen in derselben Zeichenfolge zu finden. Wenn Sie dies tun, beginnt die Suche mit der Teilzeichenfolge von str, die in der lastIndex -Eigenschaft des regulären Ausdrucks angegeben ist (test () führt auch die lastIndex -Eigenschaft voran). Angenommen, Sie haben dieses Skript:

var myRe = /ab*/g;
var str = 'abbcdefabh';
var myArray;
while ((myArray = myRe.exec(str)) !== null) {
  var msg = 'Found ' + myArray[0] + '. ';
  msg += 'Next match starts at ' + myRe.lastIndex;
  console.log(msg);
}

Dieses Skript zeigt den folgenden Text an:

Found abb. Next match starts at 3
Found ab. Next match starts at 912

Hinweis: Platzieren Sie das Literal für reguläre Ausdrücke (oder den RegExp-Konstruktor) nicht innerhalb der while-Bedingung. Andernfalls wird eine Endlosschleife erstellt, wenn aufgrund der letzten Last-Eigenschaft bei jeder Iteration eine Übereinstimmung vorliegt. Stellen Sie außerdem sicher, dass das globale Flag gesetzt ist oder eine Schleife auch hier auftritt.

11
KIM Taegyoon

Um bei der vorgeschlagenen Frage, wie durch den Titel angegeben, zu bleiben, können Sie mit String.prototype.replace() tatsächlich jede Übereinstimmung in einer Zeichenfolge durchlaufen. Mit dem folgenden Beispiel wird ein Array aller Wörter basierend auf einem regulären Ausdruck erstellt:

function getWords(str) {
  var arr = [];
  str.replace(/\w+/g, function(m) {
    arr.Push(m);
  });
  return arr;
}

var words = getWords("Where in the world is Carmen Sandiego?");
// > ["Where", "in", "the", "world", "is", "Carmen", "Sandiego"]

Wenn ich Capture-Gruppen oder sogar den Index jedes Matches abrufen wollte, könnte ich das auch tun. Das Folgende zeigt, wie jedes Match mit dem gesamten Match, der ersten Capture-Gruppe und dem Index zurückgegeben wird:

function getWords(str) {
  var arr = [];
  str.replace(/\w+(?=(.*))/g, function(m, remaining, index) {
    arr.Push({ match: m, remainder: remaining, index: index });
  });
  return arr;
}

var words = getWords("Where in the world is Carmen Sandiego?");

Nach dem Ausführen des obigen wird words wie folgt aussehen:

[
  {
    "match": "Where",
    "remainder": " in the world is Carmen Sandiego?",
    "index": 0
  },
  {
    "match": "in",
    "remainder": " the world is Carmen Sandiego?",
    "index": 6
  },
  {
    "match": "the",
    "remainder": " world is Carmen Sandiego?",
    "index": 9
  },
  {
    "match": "world",
    "remainder": " is Carmen Sandiego?",
    "index": 13
  },
  {
    "match": "is",
    "remainder": " Carmen Sandiego?",
    "index": 19
  },
  {
    "match": "Carmen",
    "remainder": " Sandiego?",
    "index": 22
  },
  {
    "match": "Sandiego",
    "remainder": "?",
    "index": 29
  }
]

Um mehrere Vorkommen ähnlich wie in PHP mit preg_match_all abzugleichen, können Sie diese Art des Denkens verwenden, um eigene zu erstellen, oder etwas wie YourJS.matchAll() verwenden. YourJS definiert diese Funktion mehr oder weniger wie folgt:

function matchAll(str, rgx) {
  var arr, extras, matches = [];
  str.replace(rgx.global ? rgx : new RegExp(rgx.source, (rgx + '').replace(/[\s\S]+\//g , 'g')), function() {
    matches.Push(arr = [].slice.call(arguments));
    extras = arr.splice(-2);
    arr.index = extras[0];
    arr.input = extras[1];
  });
  return matches[0] ? matches : null;
}
2
Chris West

Wenn jemand (wie ich) Tomalaks Methode mit Array-Unterstützung (dh Multiple Select) benötigt, ist dies hier:

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)) {
    if( params[decode(match[1])] ) {
        if( typeof params[decode(match[1])] != 'object' ) {
            params[decode(match[1])] = new Array( params[decode(match[1])], decode(match[2]) );
        } else {
            params[decode(match[1])].Push(decode(match[2]));
        }
    }
    else
        params[decode(match[1])] = decode(match[2]);
  }
  return params;
}
var urlParams = getUrlParams(location.search);

eingabe ?my=1&my=2&my=things

ergebnis 1,2,things (früher nur zurückgegeben: Dinge)

2
fedu

Verwenden Sie window.URL:

> s = 'http://www.example.com/index.html?1111342=Adam%20Franco&348572=Bob%20Jones'
> u = new URL(s)
> Array.from(u.searchParams.entries())
[["1111342", "Adam Franco"], ["348572", "Bob Jones"]]
1
jnnnnn

Wenn Sie mit map auskommen können, ist dies eine 4-Zeilen-Lösung:

var mystring = '1111342=Adam%20Franco&348572=Bob%20Jones';

var result = mystring.match(/(&|&amp;)?([^=]+)=([^&]+)/g) || [];
result = result.map(function(i) {
  return i.match(/(&|&amp;)?([^=]+)=([^&]+)/);
});

console.log(result);

Ist nicht hübsch, nicht effizient, aber zumindest ist es kompakt. ;)

1
fboes

Um Regex-Höllen zu vermeiden, können Sie Ihren ersten Treffer finden, ein Stück abhacken und versuchen, das nächste auf dem Teilstring zu finden. In C # sieht das ungefähr so ​​aus, sorry, ich habe es nicht für Sie in JavaScript portiert.

        long count = 0;
        var remainder = data;
        Match match = null;
        do
        {
            match = _rgx.Match(remainder);
            if (match.Success)
            {
                count++;
                remainder = remainder.Substring(match.Index + 1, remainder.Length - (match.Index+1));
            }
        } while (match.Success);
        return count;
0
andrew pate

Das Aufteilen scheint für mich die beste Option zu sein:

'1111342=Adam%20Franco&348572=Bob%20Jones'.split('&').map(x => x.match(/(?:&|&amp;)?([^=]+)=([^&]+)/))
0
pguardiario

Um mehrere Parameter mit demselben Namen zu erfassen, habe ich die while-Schleife in Tomalaks Methode folgendermaßen geändert:

  while (match = re.exec(url)) {
    var pName = decode(match[1]);
    var pValue = decode(match[2]);
    params[pName] ? params[pName].Push(pValue) : params[pName] = [pValue];
  }

eingabe: ?firstname=george&lastname=bush&firstname=bill&lastname=clinton

gibt zurück: {firstname : ["george", "bill"], lastname : ["bush", "clinton"]}

0
ivar

Nun ... ich hatte ein ähnliches Problem ... Ich möchte eine Inkremental-/Stufensuche mit RegExp (ZB: Suche starten ... etwas bearbeiten ... Suche bis zum letzten Treffer fortsetzen)

Nach so viel Internet-Suche ... wie immer (das macht sich jetzt zur Gewohnheit) Ich lande in StackOverflow und fand die Antwort ...

Was nicht erwähnt wird, ist "lastIndex" Ich verstehe jetzt, warum das RegExp-Objekt die "lastIndex" -Eigenschaft implementiert

0
ZEE