使用RegExp.exec提取字符串中的所有匹配项的正则表达式

246

我正在尝试解析以下类型的字符串:

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

在这里有任意数量的key:"val"对。我想要获取key名称和对应的value值。

为了好奇,我正在尝试解析Task Warrior数据库格式的字符串。

这里是我的测试字符串:

[description:"aoeu" uuid:"123sth"]

这个代码片段旨在强调键或值中可能包含除空格以外的任何字符,冒号周围不能有空格,值总是用双引号括起来。

在Node环境下,我的输出如下:

[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"也符合这种模式。如何获得所有匹配项?


1
可能是我的正则表达式有误和/或我在JavaScript中错误地使用了正则表达式功能。这似乎有效:> var s =“十五是15,八是8”;> var re = / \ d + / g; > var m = s.match(re); m = ['15','8'] - gatlin
8
JavaScript现在有一个.match()函数:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/match使用方法如下:"some string".match(/regex/g) - Stefnotch
现在你可以使用str.matchAll(regex)来迭代获取所有匹配项,包括组的元信息。因此,这个应该是被接受的答案,因为它现在得到了很好的支持。 - undefined
19个回答

7

如果您能使用matchAll,这里有个技巧:

Array.From有一个“选择器”参数,因此您可以将其投影到实际所需内容,而不是最终得到的尴尬的“match”结果数组:

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

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

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

2
现代方式! - yurenchen

3
自从ES9开始,现在有一种更简单、更好的方式来获取所有匹配项,以及有关捕获组及其索引的信息:
const string = 'Mice like to dice rice';
const regex = /.ice/gu;
for(const match of string.matchAll(regex)) {
    console.log(match);
}

// ["老鼠", index: 0, input: "老鼠喜欢切米饭", groups: undefined]

// ["切", index: 10, input: "老鼠喜欢切米饭", groups: undefined]

// ["米饭", index: 13, input: "老鼠喜欢切米饭", groups: undefined]

目前支持Chrome,Firefox和Opera。根据您阅读此内容的时间,请查看此链接以查看当前的支持情况。


1
太好了!但仍然需要记住,正则表达式应该有一个标志g,并且在调用matchAll之前,它的lastIndex应该被重置为0。 - N. Kudryavtsev

2

Use this...

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

它将返回所有匹配项的数组...这样就可以正常工作... 但请记住,它不会考虑分组。它只会返回完整的匹配项...

正则表达式必须带有标志“g”,例如/.../g - Madacol

0

我猜想,如果存在额外或缺失空格等边界情况,这个表达式可能也是一个选择:

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

如果您想要探索/简化/修改表达式,可以在regex101.com的右上方面板中找到解释。如果您愿意,您还可以在此链接中查看它如何匹配一些示例输入。

测试

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

正则表达式电路

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

enter image description here


0

const re = /^\[(?:(.+?):"(.+?)"\s*)+\]$/g
const matches = [...re.exec('[description:"aoeu" uuid:"123sth"]').entries()]
console.log(matches)

Basically, this is ES6 way to convert Iterator returned by exec to a regular Array


0
我强烈推荐使用String.match()函数,并为其创建相关的正则表达式。我的示例是针对字符串列表的,这在扫描用户输入以查找关键字和短语时经常需要使用。
    // 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"]

希望这有所帮助!

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 运行。

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

-6

这是我的答案:

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(','));

3
您的输入字符串(str)格式不正确(有太多方括号)。您只捕获了键,而未捕获值。您的代码存在语法错误并且无法执行(最后一个括号)。如果您回答已经接受答案的“旧”问题,请确保添加更多的知识和更好的答案,以超过已接受的答案。我认为您的答案没有做到这一点。 - Cleared

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接