我必须处理一个逗号分隔的字符串,其中包含三元组值并将它们转换为运行时类型,输入如下所示:
"1x2y3z,80r160g255b,48h30m50s,1x3z,255b,1h,..."
所以每个子字符串应该这样转换:
"1x2y3z" should become Vector3 with x = 1, y = 2, z = 3
"80r160g255b" should become Color with r = 80, g = 160, b = 255
"48h30m50s" should become Time with h = 48, m = 30, s = 50
我面临的问题是所有组件都是可选的(但它们保留顺序)所以以下字符串也是有效的 Vector3
、Color
和 时间
值:
"1x3z" Vector3 x = 1, y = 0, z = 3
"255b" Color r = 0, g = 0, b = 255
"1h" Time h = 1, m = 0, s = 0
到目前为止我尝试了什么?
所有组件可选
((?:\d+A)?(?:\d+B)?(?:\d+C)?)
A
、B
和 C
被替换为每种情况下的正确字母,表达式几乎可以正常工作,但它给出了两倍预期结果(一个匹配字符串,另一个匹配紧接在第一个匹配之后的空字符串),例如:
"1h1m1s" two matches [1]: "1h1m1s" [2]: ""
"11x50z" two matches [1]: "11x50z" [2]: ""
"11111h" two matches [1]: "11111h" [2]: ""
这并不出乎意料……毕竟当所有组件都为空时,空字符串与表达式匹配;所以为了解决这个问题,我尝试了以下方法:
1 到 3 量词
((?:\d+[ABC]){1,3})
但是现在,表达式匹配顺序错误甚至重复组件的字符串!:
"1s1m1h" one match, should not match at all! (wrong order)
"11z50z" one match, should not match at all! (repeated components)
"1r1r1b" one match, should not match at all! (repeated components)
至于我最后一次尝试,我尝试了第一个表达式的这个变体:
匹配从开始 ^
到结束 $
^((?:\d+A)?(?:\d+B)?(?:\d+C)?)$
它比第一个版本工作得更好,但它仍然匹配空字符串加上我应该首先标记输入然后将每个标记传递给表达式以确保测试字符串可以匹配开始(^
) 和结束 ($
) 运算符。
编辑:前瞻尝试(感谢 Casimir et Hippolyte )
阅读并(尝试)理解 regex lookahead concept 并在 Casimir et Hippolyte answer 的帮助下,我尝试了建议的表达方式:
\b(?=[^,])(?=.)((?:\d+A)?(?:\d+B)?(?:\d+C)?)\b
针对以下测试字符串:
"48h30m50s,1h,1h1m1s,11111h,1s1m1h,1h1h1h,1s,1m,1443s,adfank,12322134445688,48h"
结果非常棒!它能够完美地检测到完整的有效匹配(其他表达式在 "1s1m1h"
或 "1h1h1h"
上给了我 3 个匹配,根本不打算匹配)。不幸的是,每次发现无效匹配时它都会捕获空匹配,因此在 "1s1m1h"
、"1h1h1h"
、 之前检测到
和 ""
>"adfank""12322134445688"
,所以我修改了 Lookahead 条件以获得以下表达式:
\b(?=(?:\d+[ABC]){1,3})(?=.)((?:\d+A)?(?:\d+B)?(?:\d+C)?)\b
它去除了任何不匹配 (?:\d+[ABC]){1,3})
的字符串中的空匹配,所以空匹配就在 之前” adfank"
和 "12322134445688"
不见了,但 "1s1m1h"
、"1h1h1h"
之前的那些仍然被检测到。
所以问题是:是否存在任何正则表达式以给定顺序匹配三个三元组值,其中所有组件都是可选的但应至少由一个组件组成并且不匹配空字符串?
我使用的正则表达式工具是 C++11。
最佳答案
是的,您可以在开头添加前瞻以确保至少有一个字符:
^(?=.)((?:\d+A)?(?:\d+B)?(?:\d+C)?)$
如果您需要在更大的字符串中找到这种子字符串(因此之前无需标记化),您可以删除 anchor 并在前瞻中使用更明确的子模式:
(?=\d+[ABC])((?:\d+A)?(?:\d+B)?(?:\d+C)?)
在这种情况下,为避免误报(因为您正在寻找可能是其他内容的一部分的非常小的字符串),您可以向模式添加单词边界:
\b(?=\d+[ABC])((?:\d+A)?(?:\d+B)?(?:\d+C)?)\b
注意:在逗号分隔的字符串中:(?=\d+[ABC])
可以替换为(?=[^,])
关于c++ - 具有所有组件可选的正则表达式,如何避免空匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30235325/