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

[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"也匹配此模式。如何找回所有比赛?

评论

可能是我的regex错误和/或我只是在JavaScript中错误地使用了regex工具。这似乎可行:> var s =“十五是15,八是8”; > var re = / \ d + / g; > var m = s.match(re); m = ['15','8']

Javascript现在具有.match()函数:developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/…像这样使用:“一些字符串” .match(/ regex / g)

#1 楼

继续循环调用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/

评论


为什么不花一会儿而不是……一会儿呢?

–浓汤
2011年6月12日18:14

使用while循环会使初始化m有点尴尬。您要么必须编写while(m = re.exec(s)),这是一种反模式IMO,要么必须编写m = re.exec(s);而(m){... m = re.exec(s); }。我更喜欢do ... if ...虽然成语,但其他技巧也可以。

– Lawnsea
2011年6月12日18:21

在铬中这样做导致我的标签崩溃。

– EdgeCaseBerg
2014-12-16 18:53

@EdgeCaseBerg您需要设置g标志,否则内部指针不会向前移动。文件。

– Tim
15年7月25日在13:45

另一点是,如果正则表达式可以匹配空字符串,那么它将是一个无限循环

–FabioCosta
17年6月8日,0:57

#2 楼

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




评论


当心:匹配项不是匹配的对象,而是匹配的字符串。例如,无法访问“除@Emran:emran26,@ Raju:raju13和@Noman:noman42以外的所有人”中的组。match(/ @(\ w +):(\ w +)/ g)(其中将返回[“ @Emran:emran26”,“ @ Raju:raju13”,“ @ Noman:noman42”])

– Madprog
17年8月18日在9:46



@madprog,对,这是最简单的方法,但在组值很重要时不适用。

–阿尼斯
17年9月13日在10:02

这对我不起作用。我只有第一场比赛。

–安东尼·罗伯茨(Anthony Roberts)
18/12/31在19:38

@AnthonyRoberts,您必须添加“ g”标志。 / @ \ w / g或新的RegExp(“ @ \\ w”,“ g”)

– Aruna希思
19年1月28日在7:50

#3 楼

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

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

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


评论


我认为这太复杂了。但是,很高兴知道做一件简单事情的不同方法(我赞成你的回答)。

– Arashsoft
16年5月12日在21:09

这是违反直觉的代码。您不会以任何有意义的意义“替代”任何东西。它只是出于某些目的而利用某些功能。

–卢克·毛勒(Luke Maurer)
17年7月27日在19:43

@dudewad如果工程师只是在遵循规则而又没有开箱即用的想法,那么我们甚至都不会立即考虑拜访其他星球;

–克里斯托弗(Christophe)
18年9月7日在22:56

@dudewad对不起,我在这里看不到懒惰的部分。如果将完全相同的方法称为“过程”而不是“替换”,则可以。恐怕您只是停留在术语上。

–克里斯托弗(Christophe)
18-09-16在23:43

@Christophe我绝对不会停留在术语上。我被困在干净的代码上。出于某种目的而使用旨在达到某一目的的事物被称为“ hacky”。它创建了难以理解的混乱代码,并且经常在性能方面遭受损失。您在没有正则表达式的情况下回答了这个问题,其本身的事实使其成为无效答案,因为OP要求使用正则表达式来解决此问题。但是,我认为保持这个社区的高标准很重要,这就是为什么我坚持上面所说的。

– dudewad
18-09-19在7:54

#4 楼

这是一个解决方案

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

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


这是基于Grasssea的答案,但要短一些。

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

#5 楼

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至关重要,以便在每次执行中向前移动指针。

评论


是。递归看起来优雅而凉爽。迭代循环简单明了,易于维护和调试。

– Andy N
19年4月5日在22:49

我喜欢递归解决方案,因为;我喜欢递归解决方案

–本绕组
12月17日4:28

#6 楼

我们终于开始看到内置的matchAll函数,有关说明和兼容性表,请参见此处。截至2020年5月,似乎支持Chrome,Edge,Firefox和Node.js(12+),但不支持IE,Safari和Opera。好像它是在2018年12月草拟的,所以给它一些时间来访问所有浏览器,但我相信它会到达那里。它还会为每次比赛返回捕获组!这样您就可以执行

 matchAll 


,似乎每个匹配对象都使用相同的对象格式为// 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()indexinput。因此,它看起来像:

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


有关groups的更多信息,还有一个Google开发人员页面。也有polyfills / shimms。

评论


我真的很喜欢,但是它还没有完全落入Firefox 66.0.3中。 Caniuse尚无相关支持列表。我很期待这个。我确实在Chromium 74.0.3729.108中看到了它的工作。

–Lonnie Best
19年5月7日在22:30



@LonnieBest是的,您可以看到我链接的MDN页面的兼容性部分。似乎Firefox在版本67中开始支持它。如果您要交付产品,仍然不建议使用它。有可用的填充胶/垫片,我已将其添加到答案中

– woojoo666
19年5月8日在1:55

#7 楼

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

var bob = "&gt; bob &lt;";
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: [&gt;, &lt;]


#8 楼

如果您有ES9
(意味着您的系统:Chrome,Node.js,Firefox等支持Ecmascript 2019或更高版本)
使用新的yourString.matchAll( /your-regex/ )
如果您没有ES9
如果您使用的是较旧的系统,则可以使用以下功能轻松复制和粘贴
 function findAll(regexPattern, sourceString) {
    let output = []
    let match
    // make sure the pattern has the global flag
    let regexPatternWithGlobal = RegExp(regexPattern,[...new Set("g"+regexPattern.flags)].join(""))
    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 ] ]


#9 楼

可迭代项更好:

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


评论


错字:if(m)应该是if(match)

–博耶
18年8月8日在9:07

数组已经可以迭代,因此每个返回匹配数组的人也都可以迭代。更好的是,如果您控制台记录一个数组,则浏览器实际上可以打印出内容。但是控制台记录通用的可迭代对象只会让您[object Object] {...}

– StJohn3D
18-10-31在12:47

所有数组都是可迭代的,但并非所有可迭代对象都是数组。如果您不知道呼叫者需要做什么,则可迭代的优先级更高。例如,如果只希望第一个匹配,则可迭代的效率更高。

–sdgfsdh
18-10-31在13:13

您的梦想正在变成现实,浏览器正在推出对内置matchAll的支持,所有返回可迭代的:D

– woojoo666
19年4月8日在12:19

我遇到了这个答案,matchAll实现。我为支持它的浏览器JS写了一些代码,但是Node实际上不支持。这与matchAll的行为相同,因此我不必重写东西-干杯!

–user37309
19年4月12日,1:13

#10 楼

这是我获取匹配项的功能:

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

// Example:

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

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


评论


当您忘记添加全局标志时,此解决方案可防止无限循环。

–user68311
19年11月23日在23:22

#11 楼

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


// [“ mice”,索引: 0,输入:“老鼠要切饭”,组:
未定义]
// [“骰子”,索引:13,输入:“老鼠要切饭的骰子”,
组:未定义]
// [“大米”,索引:18,输入:“老鼠要切成小方块
大米”,组:未定义]

Chrome当前支持,Firefox,Opera。根据您阅读本文的时间,请查看此链接以查看其当前支持。

评论


高超!但是,请记住,正则表达式应具有标志g,并且在调用matchAll之前将其lastIndex重置为0,这仍然很重要。

– N. Kudryavtsev
19年11月7日在10:54

#12 楼

使用它...

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


它将返回所有匹配项的数组...那将很好用....
但请记住它赢了不会考虑团体。它将只返回全部匹配项...

#13 楼

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

#14 楼

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

我ve使答案中的正则表达式更加清晰(这不是解决您的确切问题的方法)。

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

#15 楼

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

顺序保留在结果列表中。

潜在的缺点是


它为每个匹配项都克隆正则表达式。 br />结果的形式与预期的解决方案不同。您需要再处理一次。

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


#16 楼

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

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





RegEx Circuit

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



#17 楼

如果您能够使用matchAll,这是一个技巧: >
Array.from(str.matchAll(regexp), m => m[0]);

如果您已命名组,例如(Array.From)您可以执行以下操作:
Array.from(str.matchAll(regexp), m => m.groups.firstName);


#18 楼

这是我的答案:

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


评论


您的输入字符串(str)的格式错误(括号内过多)。您仅捕获键,而不捕获值。您的代码语法错误,并且不执行(最后一个括号)。如果您用已经接受的答案回答“老”问题,请确保您添加的知识和更好的答案要比已经接受的答案多。我认为您的回答不会那样做。

–已清除
17年7月3日在6:34