How can I match multiple occurrences with a regex

2019-01-02 15:09发布

I am trying to parse url-encoded strings that are made up of key=value pairs separated by either & or &.

The following will only match the first occurrence, breaking apart the keys and values into separate result elements:

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

The results for the string '1111342=Adam%20Franco&348572=Bob%20Jones' would be:

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

Using the global flag, 'g', will match all occurrences, but only return the fully matched sub-strings, not the separated keys and values:

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

The results for the string '1111342=Adam%20Franco&348572=Bob%20Jones' would be:

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

While I could split the string on & and break apart each key/value pair individually, is there any way using JavaScript's regular expression support to match multiple occurrences of the pattern /(?:&|&)?([^=]+)=([^&]+)/ similar to PHP's preg_match_all() function?

I'm aiming for some way to get results with the sub-matches separated like:

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

or

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

14条回答
伤终究还是伤i
2楼-- · 2019-01-02 15:40

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

Finding successive matches

If your regular expression uses the "g" flag, you can use the exec() method multiple times to find successive matches in the same string. When you do so, the search starts at the substring of str specified by the regular expression's lastIndex property (test() will also advance the lastIndex property). For example, assume you have this script:

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);
}

This script displays the following text:

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

Note: Do not place the regular expression literal (or RegExp constructor) within the while condition or it will create an infinite loop if there is a match due to the lastIndex property being reset upon each iteration. Also be sure that the global flag is set or a loop will occur here also.

查看更多
还给你的自由
3楼-- · 2019-01-02 15:40

Just to stick with the proposed question as indicated by the title, you can actually iterate over each match in a string using String.prototype.replace(). For example the following does just that to get an array of all words based on a regular expression:

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"]

If I wanted to get capture groups or even the index of each match I could do that too. The following shows how each match is returned with the entire match, the 1st capture group and the index:

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?");

After running the above, words will be as follows:

[
  {
    "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
  }
]

In order to match multiple occurrences similar to what is available in PHP with preg_match_all you can use this type of thinking to make your own or use something like YourJS.matchAll(). YourJS more or less defines this function as follows:

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;
}
查看更多
登录 后发表回答