正则表达式与所有组件可选,如何避免空匹配
regex with all components optionals, how to avoid empty matches
我必须处理一个逗号分隔的字符串,它包含值的三元组,并将它们转换为运行时类型,输入看起来像:
"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
和Time
值:
"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向前看的概念,并在Casimir et Hippolyte答案的帮助下,我尝试了建议的表达式:
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)?)$
如果您需要在更大的字符串中找到这种子字符串(因此之前不需要标记),您可以删除锚并在forward中使用更显式的子模式:
(?=d+[ABC])((?:d+A)?(?:d+B)?(?:d+C)?)
在这种情况下,为了避免误报(因为您正在寻找可能是其他内容一部分的非常小的字符串),您可以向模式添加单词边界:
b(?=d+[ABC])((?:d+A)?(?:d+B)?(?:d+C)?)b
注意:在逗号分隔的字符串中:(?=d+[ABC])
可以用(?=[^,])
代替
我想这可能会奏效。
我键入字符串的开头以匹配^
或逗号分隔符,
以修复每个匹配的开始:(?:^|,)
.
的例子:
#include <regex>
#include <iostream>
const std::regex r(R"~((?:^|,)((?:d+[xrh])?(?:d+[ygm])?(?:d+[zbs])?))~");
int main()
{
std::string test = "1x2y3z,80r160g255b,48h30m50s,1x3z,255b";
std::sregex_iterator iter(test.begin(), test.end(), r);
std::sregex_iterator end_iter;
for(; iter != end_iter; ++iter)
std::cout << iter->str(1) << 'n';
}
输出:
1x2y3z
80r160g255b
48h30m50s
1x3z
255b
这是你想要的吗?
编辑:如果你真的想让空表达式不匹配,那么据我所知,你必须像这样输入每一个排列:
const std::string A = "(?:\d+[xrh])";
const std::string B = "(?:\d+[ygm])";
const std::string C = "(?:\d+[zbs])";
const std::regex r("(?:^|,)(" + A + B + C + "|" + A + B + "|" + A + C + "|" + B + C + "|" + A + "|" + B + "|" + C + ")");
- C++避免重复声明的语法是什么
- 在没有太多条件句的情况下,我如何避免被零除
- 如何将 txt 文件中的行分隔为组件C++
- 如何重构类层次结构以避免菱形问题
- 函数何时会在c++中包含stack_Unwind_Resume调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 以下示例中如何避免代码复制?C++/库达
- Python中的for循环与C++有何不同
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 是否应该在模板化代码中完全避免const
- 我应该避免多重实现继承吗
- 为了方便起见,我应该避免公开私有字段变量吗
- 使用不同的CRT将新的C++代码与旧的(二进制)组件隔离开来的最佳方法是什么
- 到连接组件算法的问题(递归)
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 避免在C++中重复子类定义
- 两个 COM 组件中 ENUM 的重复条目
- "Inverse SFINAE"避免模棱两可的过载
- 为什么 gcc 会产生这种奇怪的组件与叮当声?
- 正则表达式与所有组件可选,如何避免空匹配