Javascript正则表达式分组奇怪的行为:仅在第二次尝试时匹配

时间:2017-09-20 23:43:00

标签: javascript regex

真的很难为这个问题找到正确的措辞,我确信答案会在某处发布,而且与完全不了解RegExp.prototype.exec()的工作方式有关。

我有一个大型对象,其键是字符串并遵循此模式。 "foo.bar.baz": 'test'其中每个段的长度都是任意长度,所有键都以foo开头,但其余部分各不相同。我需要构建一个包含所有中间段的数组,即。 '杆'在这个例子中。为此,我使用简单的正则表达式分组。

const myRegex = /foo\.([^\.]*)\./g

字符串以foo开头,然后是"。",然后捕获所有内容,直到下一个"。"。

使用上述键迭代对象,我想每次将中间部分(bar)附加到数组中,不包括重复项。

for(const key in myObject){           //loop over each key in the object
  const matches = []
  match = myRegex.exec(key)
  if (match) {
    if (matches.indexOf(match[1]) === -1) {    //exclude duplicates
      matches.push(match[1])
    }
  }

奇怪的行为是,这仅适用于具有多个匹配项的所有第二个段。例如,给出了下面的对象。

{
    'foo.bar.bar': 'test',
    'foo.bar.baz': 'test',
    'foo.baz.bar': 'test',
    'foo.baz.baz': 'test',
    'foo.bam.bar': 'test'
}

只有bar,baz才会被推到比赛中。如果将foo.bam.baz: 'test'添加到对象,则匹配bam并将其推送到数组。如果删除foo.bar.xfoo.baz.x中的一个,则不会推送该密钥。它似乎只是在第二次尝试时匹配,我无法弄清楚原因。

非常感谢任何见解。

2 个答案:

答案 0 :(得分:1)

看起来正则表达式对象是有状态的:

var myRegex = /foo\.([^\.]*)\./g;

console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
console.log(myRegex.exec("foo.bar.bar"))
(2) ["foo.bar.", "bar", index: 0, input: "foo.bar.bar"]
null
(2) ["foo.bar.", "bar", index: 0, input: "foo.bar.bar"]
null
(2) ["foo.bar.", "bar", index: 0, input: "foo.bar.bar"]
null
(2) ["foo.bar.", "bar", index: 0, input: "foo.bar.bar"]
null
(2) ["foo.bar.", "bar", index: 0, input: "foo.bar.bar"]

答案 1 :(得分:0)

您可以使用Object.keys()获取对象的属性值,.map()来迭代属性,RegExp /^foo\.|\.\w+$/g以匹配"foo""."后跟一个或多个单词字符,后跟字符串结尾Set,以从结果集合中删除重复项,然后将Set转换为数组



const o = {
    'foo.bar.bar': 'test',
    'foo.bar.baz': 'test',
    'foo.baz.bar': 'test',
    'foo.baz.baz': 'test',
    'foo.bam.bar': 'test'
}

let matches = [...new Set(Object.keys(o).map(prop => 
                prop.replace(/^foo\.|\.\w+$/g, "")))];

console.log(matches);