如何在JavaScript中检索正则表达式的所有匹配项?

时间:2011-06-12 17:27:40

标签: javascript regex

我是正则表达式的新手。我正在尝试解析以下类型的字符串:

[key:"val" key2:"val2"]

里面有任意键:里面有“val”对。我想抓住关键名称和价值。 对于那些好奇的我正在尝试解析任务战士的数据库格式。这是我的测试字符串:

[description:"aoeu" uuid:"123sth"]这是为了强调除了空格之外的任何东西都可以在键或值中,冒号周围没有空格,值总是用双引号。在节点中,这是我的输出:

[deuteronomy][gatlin][~]$ node
> var re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
> re.exec('[description:"aoeu" uuid:"123sth"]');
[ '[description:"aoeu" uuid:"123sth"]',
  'uuid',
  '123sth',
  index: 0,
  input: '[description:"aoeu" uuid:"123sth"]' ]

但是description:"aoeu"也符合这种模式。我怎样才能收到所有比赛?

19 个答案:

答案 0 :(得分:182)

继续在循环中调用re.exec(s)以获取所有匹配项:

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';
var m;

do {
    m = re.exec(s);
    if (m) {
        console.log(m[1], m[2]);
    }
} while (m);

尝试使用此JSFiddle:https://jsfiddle.net/7yS2V/

答案 1 :(得分:84)

要遍历所有匹配项,您可以使用replace函数:

var re = /\s*([^[:]+):\"([^"]+)"/g;
var s = '[description:"aoeu" uuid:"123sth"]';

s.replace(re, function(match, g1, g2) { console.log(g1, g2); });

答案 2 :(得分:84)

str.match(pattern),如果pattern具有全局标记g,则会将所有匹配作为数组返回。

例如:



const str = 'All of us except @Emran, @Raju and @Noman was there';
console.log(
  str.match(/@\w*/g)
);
// Will log ["@Emran", "@Raju", "@Noman"]




答案 3 :(得分:52)

这是一个解决方案

var s = '[description:"aoeu" uuid:"123sth"]';

var re = /\s*([^[:]+):\"([^"]+)"/g;
var m;
while (m = re.exec(s)) {
  console.log(m[1], m[2]);
}

这是基于lawsea的答案,但更短。

请注意,必须设置`g'标志以在调用之前将内部指针向前移动。

答案 4 :(得分:13)

str.match(/regex/g)

以数组形式返回所有匹配项。

如果出于某种神秘的原因,您需要exec附带的其他信息,作为以前答案的替代方法,则可以使用递归函数代替循环,如下所示(看起来也很酷) 。

function findMatches(regex, str, matches = []) {
   const res = regex.exec(str)
   res && matches.push(res) && findMatches(regex, str, matches)
   return matches
}

// Usage
const matches = findMatches(/regex/g, str)

如之前的评论所述,在正则表达式定义的末尾使用g可以在每次执行中向前移动指针。

答案 5 :(得分:8)

基于Agus的功能,但我更喜欢只返回匹配值:

var bob = "> bob <";
function matchAll(str, regex) {
    var res = [];
    var m;
    if (regex.global) {
        while (m = regex.exec(str)) {
            res.push(m[1]);
        }
    } else {
        if (m = regex.exec(str)) {
            res.push(m[1]);
        }
    }
    return res;
}
var Amatch = matchAll(bob, /(&.*?;)/g);
console.log(Amatch);  // yeilds: [>, <]

答案 6 :(得分:6)

Iterables更好:

const matches = (text, pattern) => ({
  [Symbol.iterator]: function * () {
    const clone = new RegExp(pattern.source, pattern.flags);
    let match = null;
    do {
      match = clone.exec(text);
      if (match) {
        yield match;
      }
    } while (match);
  }
});

循环中的用法:

for (const match of matches('abcdefabcdef', /ab/g)) {
  console.log(match);
}

或者如果你想要一个数组:

[ ...matches('abcdefabcdef', /ab/g) ]

答案 7 :(得分:3)

这是我获得比赛的功能:

function getAllMatches(regex, text) {
    if (regex.constructor !== RegExp) {
        throw new Error('not RegExp');
    }

    var res = [];
    var match = null;

    if (regex.global) {
        while (match = regex.exec(text)) {
            res.push(match);
        }
    }
    else {
        if (match = regex.exec(text)) {
            res.push(match);
        }
    }

    return res;
}

var regex = /abc|def|ghi/g;
var res = getAllMatches(regex, 'abcdefghi');

res.forEach(function (item) {
    console.log(item[0]);
});

答案 8 :(得分:3)

我们终于开始看到内置的matchAll函数,请参见here for the description and compatibility table。截至2019年4月,似乎支持Chrome和Firefox,但不支持IE,Edge,Opera或Node.js.好像是drafted in December 2018,所以请给它一些时间来访问所有浏览器,但我相信它会到达那里。

内置的matchAll函数很不错,因为它返回了iterable。它还会为每次比赛返回捕获组!所以你可以做类似的事情

// get the letters before and after "o"
let matches = "stackoverflow".matchAll(/(\w)o(\w)/g);

for (match of matches) {
    console.log("letter before:" + match[1]);
    console.log("letter after:" + match[2]);
}

arrayOfAllMatches = [...matches]; // you can also turn the iterable into an array

似乎每个匹配对象都使用与match()相同的格式。因此,每个对象都是匹配和捕获组的数组,以及三个附加属性indexinputgroups。看起来像这样:

[<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>]

有关matchAll的更多信息,还有Google developers page。也有polyfills/shims可用。

答案 9 :(得分:2)

如果您的系统(Chrome / Node.js / Firefox)支持ES9,请使用新的.matchAll()。如果你有一个较旧的系统,这里有一个易于复制和粘贴的功能

function findAll(regexPattern, sourceString) {
    let output = []
    let match
    // make sure the pattern has the global flag
    let regexPatternWithGlobal = RegExp(regexPattern,"g")
    while (match = regexPatternWithGlobal.exec(sourceString)) {
        // get rid of the string copy
        delete match.input
        // store the match data
        output.push(match)
    } 
    return output
}

示例用法:

console.log(   findall(/blah/g,'blah1 blah2')   ) 

输出:

[ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ]

答案 10 :(得分:1)

自ES9开始,现在有了一种更简单,更好的方式来获取所有匹配项以及有关捕获组及其索引的信息:

const string = 'Mice like to dice rice';
const regex = /.ice/gu;
for(const match of string.matchAll(regex)) {
    console.log(match);
}
  

// [[小鼠],索引:0,输入:“老鼠要切饭”,组:   未定义]

     

// [“骰子”,索引:13,输入:“老鼠要切饭”,   组:未定义]

     

// [“大米”,索引:18,输入:“老鼠喜欢切成小方块   大米”,组:未定义]

Chrome,Firefox,Opera当前支持它。根据您阅读本文的时间,请检查this link以查看其当前支持。

答案 11 :(得分:0)

使用此...

var all_matches = your_string.match(re);
console.log(all_matches)

它将返回所有匹配的数组......这样可以正常工作.... 但请记住,它不会占用群组。它只会返回完整的匹配...

答案 12 :(得分:0)

我肯定会建议使用String.match()函数,并为其创建相关的RegEx。我的例子是一个字符串列表,在扫描关键字和短语的用户输入时通常是必需的。

    // 1) Define keywords
    var keywords = ['apple', 'orange', 'banana'];

    // 2) Create regex, pass "i" for case-insensitive and "g" for global search
    regex = new RegExp("(" + keywords.join('|') + ")", "ig");
    => /(apple|orange|banana)/gi

    // 3) Match it against any string to get all matches 
    "Test string for ORANGE's or apples were mentioned".match(regex);
    => ["ORANGE", "apple"]

希望这有帮助!

答案 13 :(得分:0)

这并不能真正解决您遇到的更复杂的问题,但是无论如何我都会发布此消息,因为它对于那些没有像您一样进行全局搜索的人来说是一个简单的解决方案。

我已经简化了答案中的正则表达式,使其更加清晰(这不是您确切问题的解决方案)。

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

// We only want the group matches in the array
function purify_regex(reResult){

  // Removes the Regex specific values and clones the array to prevent mutation
  let purifiedArray = [...reResult];

  // Removes the full match value at position 0
  purifiedArray.shift();

  // Returns a pure array without mutating the original regex result
  return purifiedArray;
}

// purifiedResult= ["description", "aoeu"]

这看起来比评论更冗长,这就是没有评论的样子

var re = /^(.+?):"(.+)"$/
var regExResult = re.exec('description:"aoeu"');
var purifiedResult = purify_regex(regExResult);

function purify_regex(reResult){
  let purifiedArray = [...reResult];
  purifiedArray.shift();
  return purifiedArray;
}

请注意,所有不匹配的组都将在数组中列为undefined值。

此解决方案使用ES6扩展运算符来净化正则表达式特定值的数组。如果需要IE11支持,则需要通过Babel运行代码。

答案 14 :(得分:0)

这是一个没有while循环的单行解决方案

订单保留在结果列表中。

潜在的弊端是

  1. 它会为每个匹配项克隆正则表达式。
  2. 结果的形式与预期解决方案不同。您需要再处理一次。
let re = /\s*([^[:]+):\"([^"]+)"/g
let str = '[description:"aoeu" uuid:"123sth"]'

(str.match(re) || []).map(e => RegExp(re.source, re.flags).exec(e))

[ [ 'description:"aoeu"',
    'description',
    'aoeu',
    index: 0,
    input: 'description:"aoeu"',
    groups: undefined ],
  [ ' uuid:"123sth"',
    'uuid',
    '123sth',
    index: 0,
    input: ' uuid:"123sth"',
    groups: undefined ] ]

答案 15 :(得分:0)

我的猜测是,如果存在边缘情况,例如多余或缺少空格,则边界较少的表达式也可能是一个选择:

^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$

  

如果您想探索/简化/修改表达式,可以   在右上角的面板上进行了说明   regex101.com。如果您愿意,   也可以在this link中观看它的匹配方式   针对一些样本输入。


测试

const regex = /^\s*\[\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*([^\s\r\n:]+)\s*:\s*"([^"]*)"\s*\]\s*$/gm;
const str = `[description:"aoeu" uuid:"123sth"]
[description : "aoeu" uuid: "123sth"]
[ description : "aoeu" uuid: "123sth" ]
 [ description : "aoeu"   uuid : "123sth" ]
 [ description : "aoeu"uuid  : "123sth" ] `;
let m;

while ((m = regex.exec(str)) !== null) {
    // This is necessary to avoid infinite loops with zero-width matches
    if (m.index === regex.lastIndex) {
        regex.lastIndex++;
    }
    
    // The result can be accessed through the `m`-variable.
    m.forEach((match, groupIndex) => {
        console.log(`Found match, group ${groupIndex}: ${match}`);
    });
}

RegEx电路

jex.im可视化正则表达式:

enter image description here

答案 16 :(得分:0)

如果您希望使用一种更具功能性的方法并避免循环,则只需调用一个函数,直到结果为null,然后在每个捕获中将字符串切成捕获组的位置即可。

// The MatchAll Function
function matchAll (regexp, input, matches = []) {
  
  const regex = regexp.exec(input)

  if (regex === null) return matches

  // Filter out any undefined results
  const matched = regex.filter(i => i)
  
  // Destruct some common used values
  const { index } = regex
  const [ full, g1, g2, g3] = matched

  // Slice the input string to last match
  const string = input.slice(index + full.length)
  
  // Do something with the captured groups
  // Push this into an array
  matches.push({
    prop: 'H' + g1 + g3 + g3 + 'ary ' + g2
  })

  // Return
  return matchAll(regexp, string) 

}

// Record of matches
const matches = []

// The RegExp, we are looking for some random letters / words in string
const regExp = new RegExp(/(i{1}).*(did).*(l{1})/)

// An example string to parse
const testString = `Jeffrey Epstein didn't kill himself!`

// Run
matchAll(regExp, testString, matches)

// Returned Result
console.log(matches)

答案 17 :(得分:0)

如果您可以使用 matchAll,这里有一个技巧:

Array.From 有一个“选择器”参数,因此您可以将其投影到您真正需要的位置,而不是以一系列尴尬的“匹配”结果结束:

Array.from(str.matchAll(regexp), m => m[0]);

如果您已命名组,例如。 (/(?<firstname>[a-z][A-Z]+)/g) 你可以这样做:

Array.from(str.matchAll(regexp), m => m.groups.firstName);

答案 18 :(得分:-5)

以下是我的回答:

var str = '[me nombre es] : My name is. [Yo puedo] is the right word'; 

var reg = /\[(.*?)\]/g;

var a = str.match(reg);

a = a.toString().replace(/[\[\]]/g, "").split(','));