我如何匹配多个匹配的正则expression式类似于PHP的preg_match_all()?

我正试图parsing由&&分隔的key = value对组成的url编码的string&

以下仅匹配第一个匹配项,将键和值拆分为单独的结果元素:

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

string'1111342 = Adam%20Franco&348572 = Bob%20Jones'的结果是:

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

使用全局标志“g”将会匹配所有的匹配项,但是只返回完全匹配的子串,而不是分离的键和值:

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

string'1111342 = Adam%20Franco&348572 = Bob%20Jones'的结果是:

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

虽然我可以分割string和分开每个键/值对,是否有任何方式使用JavaScript的正则expression式支持匹配模式/(?:&|&)?([^=]+)=([^&]+)/类似于PHP的preg_match_all()函数?

我打算以某种方式获得结果的子比赛分离如下:

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

要么

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

我会build议一个替代正则expression式,使用子组来分别捕获参数的名称和值:

 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是一个对象:

 {
   f:“q”
  地理编码:“”
   hl:“de”
  即:“UTF8”
   iwloc:“addr”
   ll:“50.116616,8.680573”
   q:“法兰克福”
   sll:“50.106047,8.679886”
  来源:“s_q”
   spn:“0.35972,0.833588”
   sspn:“0.370369,0.833588”
   z:“11”
 }

正则expression式分解如下:

 (?:#未捕获组
   \?|&#“?” 要么 ”&”
   (?:放大器;)?  #(允许“&”,错误的HTML编码的URL)
 )#结束非捕获组
 (#组1
   [^ =&#] +#除“=”,“&”或“#”之外的任何字符; 至less一次
 )#结束组1  - 这将是参数的名称
 (?:#未捕获组
   =?  #一个“=”,可选
   (#组2
     [^&#] *#除“&”或“#”之外的任何字符; 任何次数
   )#结束组2  - 这将是参数的值
 )#结束非捕获组

您需要使用“g”开关进行全局search

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

如果您不想依赖运行exec样式匹配的“盲目匹配”,那么JavaScript就会内置匹配全部function,但是它是replace函数调用的一部分,当使用“如何处理捕获组“ 处理function :

 var data = {}; var getKeyValue = function(a,b,c,d) { data[c] = d; }; mystring.replace(/(?:&|&)?([^=]+)=([^&]+)/g, getKeyValue); 

完成。 而不是使用捕获组处理函数来实际返回replacestring(为了replace处理,第一个arg,这里称为here,是全模式匹配,后续args是单独的捕获组,在这种情况下, b是group 1, c group 2等),我们只需采取组2和3捕获,并caching那对。

所以,不要写复杂的parsing函数,记住JavaScript中的“matchAll”函数只是用replace句柄函数“replace”,并且可以有很多模式匹配的效率。

为了捕获组,我习惯于在PHP中使用preg_match_all ,并试图在这里复制它的function:

 <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 = /[az]+(\d+)/g.execAll(someTxt); // Output [["abc123", "123"], ["def456", "456"], ["ghi890", "890"]] </script> 

设置全局匹配的g修饰符:

 /…/g 

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

寻找连续的比赛

如果您的正则expression式使用“g”标志,则可以多次使用exec()方法在同一个string中查找连续的匹配项。 当你这样做的时候,search从正则expression式的lastIndex属性指定的str的子string开始(test()也将前进lastIndex属性)。 例如,假设你有这个脚本:

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

该脚本显示以下文本:

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

注意:不要将正则expression式(或RegExp构造函数)置于while条件中,否则将在每次迭代时重置lastIndex属性导致匹配时创build无限循环。 还要确保全局标志被设置,否则在这里也会出现循环。

如果有人(比如我)需要Tomalak的方法支持数组(如多选),这里是:

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

input?my=1&my=2&my=things

结果1,2,things (以前只返回:东西)

只要坚持提出的问题如标题所示,您实际上可以使用String.prototype.replace()迭代string中的每个匹配。 例如下面的代码就是基于正则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"] 

如果我想获得捕获组,甚至每场比赛的索引,我也可以这样做。 以下显示每个比赛如何与整个比赛,第一个捕获组和索引一起返回:

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

运行完上面的内容后, words将会如下所示:

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

为了匹配多个与preg_match_all可用的相似的事件,您可以使用这种types的思维来创build自己的或使用类似YourJS.matchAll()东西。 YourJS或多或less地定义这个函数如下:

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

如果您可以使用map这是一个四线解决scheme:

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

为了使用相同的名称捕获几个参数,我修改了Tomalak方法中的while循环,如下所示:

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

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

返回: {firstname : ["george", "bill"], lastname : ["bush", "clinton"]}

那么…我有一个类似的问题…我想用RegExp的增量/步骤search(例如:开始search…做一些处理…继续search,直到最后一场比赛)

经过大量的互联网search…像往常一样(这是一个习惯现在)我最终在StackOverflow并find答案…

什么是不被提及和要提及的是“ lastIndex ”我现在明白为什么RegExp对象实现“ lastIndex ”属性

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

拆分它看起来对我来说是最好的select:

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