RegEx for matching Taskwarrior data format
我正在尝试解析以下类型的字符串:
1 | [key:"val" key2:"val2"] |
哪里有任意键:里面有"val"对。 我想抓住关键名称和价值。
对于那些好奇的我正在尝试解析任务战士的数据库格式。
这是我的测试字符串:
1 | [description:"aoeu" uuid:"123sth"] |
这是为了强调除了空格之外的任何东西都可以在键或值中,冒号周围没有空格,值总是用双引号。
在节点中,这是我的输出:
1 2 3 4 5 6 7 8 | [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"]' ] |
但
继续在循环中调用
1 2 3 4 5 6 7 8 9 10 | 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 2 3 4 5 | const str = 'All of us except @Emran, @Raju and @Noman was there'; console.log( str.match(/@\w*/g) ); // Will log ["@Emran","@Raju","@Noman"] |
要遍历所有匹配项,可以使用
1 2 3 4 | var re = /\s*([^[:]+):"([^"]+)"/g; var s = '[description:"aoeu" uuid:"123sth"]'; s.replace(re, function(match, g1, g2) { console.log(g1, g2); }); |
这是一个解决方案
1 2 3 4 5 6 7 | 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'标志以将内部指针向前移动到调用之间。
1 | str.match(/regex/g) |
将所有匹配作为数组返回。
如果出于某种神秘的原因,你需要附加信息附带
1 2 3 4 5 6 7 8 | 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) |
如前面的注释中所述,在正则表达式定义结束时使用
基于Agus的功能,但我更喜欢只返回匹配值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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: [>, <] |
Iterables更好:
1 2 3 4 5 6 7 8 9 10 11 12 | 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); } }); |
循环使用:
1 2 3 | for (const match of matches('abcdefabcdef', /ab/g)) { console.log(match); } |
或者如果你想要一个数组:
1 | [ ...matches('abcdefabcdef', /ab/g) ] |
我们终于开始看到内置的
内置的
1 2 3 4 5 6 7 8 9 | // 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 |
似乎每个匹配对象使用与
1 | [<match>, <group1>, <group2>, ..., index: <match offset>, input: <original string>, groups: <named capture groups>] |
有关
这是我获得比赛的功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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]); }); |
如果您的系统(Chrome / Node.js / Firefox)支持ES9,请使用新的
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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 } |
示例用法:
1 | console.log( findAll(/blah/g,'blah1 blah2') ) |
输出:
1 | [ [ 'blah', index: 0 ], [ 'blah', index: 6 ] ] |
从ES9开始,现在有一种更简单,更好的方式来获取所有匹配项,以及有关捕获组及其索引的信息:
1 2 3 4 5 | const string = 'Mice like to dice rice'; const regex = /.ice/gu; for(const match of string.matchAll(regex)) { console.log(match); } |
// ["mice", index: 0, input:"mice like to dice rice", groups:
undefined]// ["dice", index: 13, input:"mice like to dice rice",
groups: undefined]// ["rice", index: 18, input:"mice like to dice
rice", groups: undefined]
它目前支持Chrome,Firefox,Opera。根据您阅读本文的时间,请查看此链接以查看其当前支持。
我的猜测是,如果有边缘情况,如额外或缺少空格,这个边界较少的表达式也可能是一个选项:
1 2 3 4 5 | ^\s*\[\s*([^\s :]+)\s*:\s*"([^"]*)"\s*([^\s :]+)\s*:\s*"([^"]*)"\s*\]\s*$ |
If you wish to explore/simplify/modify the expression, it's been
explained on the top right panel of
regex101.com. If you'd like, you
can also watch in this
link, how it would match
against some sample inputs.
测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | const regex = /^\s*\[\s*([^\s :]+)\s*:\s*"([^"]*)"\s*([^\s :]+)\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可视化正则表达式:
我肯定会建议使用String.match()函数,并为它创建一个相关的RegEx。我的例子是一个字符串列表,在扫描关键字和短语的用户输入时通常是必需的。
1 2 3 4 5 6 7 8 9 10 | // 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"] |
希望这可以帮助!
这对你的更复杂的问题并没有真正帮助,但无论如何我都会发布这个,因为对于没有像你这样进行全局搜索的人来说,这是一个简单的解决方案。
我已经简化了答案中的正则表达式以使其更清晰(这不是解决您确切问题的方法)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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"] |
由于评论,这看起来比它更冗长,这是没有评论的样子
1 2 3 4 5 6 7 8 9 | var re = /^(.+?):"(.+)"$/ var regExResult = re.exec('description:"aoeu"'); var purifiedResult = purify_regex(regExResult); function purify_regex(reResult){ let purifiedArray = [...reResult]; purifiedArray.shift(); return purifiedArray; } |
请注意,任何不匹配的组都将在数组中列为
此解决方案使用ES6扩展运算符来纯化正则表达式特定值的数组。如果您需要IE11支持,则需要通过Babel运行代码。
这是一个没有while循环的单行解决方案。
订单将保留在结果列表中。
潜在的缺点是
1 2 3 4 | let re = /\s*([^[:]+):"([^"]+)"/g let str = '[description:"aoeu" uuid:"123sth"]' (str.match(re) || []).map(e => RegExp(re.source, re.flags).exec(e)) |
1 2 3 4 5 6 7 8 9 10 11 12 | [ [ 'description:"aoeu"', 'description', 'aoeu', index: 0, input: 'description:"aoeu"', groups: undefined ], [ ' uuid:"123sth"', 'uuid', '123sth', index: 0, input: ' uuid:"123sth"', groups: undefined ] ] |
用这个...
1 2 | var all_matches = your_string.match(re); console.log(all_matches) |
它将返回所有匹配的数组......这样可以正常工作....
但请记住,它不会占用群组。它只会返回完整的匹配...
这是我的答案:
1 2 3 4 5 6 7 | 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(',')); |