使用 Boost::regex 进行正则表达式组匹配
Regular expression group matching using Boost::regex
我有格式字符串:
7XXXX 8YYYY 9ZZZZ 0LLLL 7XXXX 8YYYY 9ZZZZ 0LLLL
,
- 其中
7XXXX 8YYYY 9ZZZZ 0LLLL
组可以重复任意次数; - X、Y、Z、L 是数字;
- 从 7,8,9,0 开始的组都按顺序进行
- 可能会缺少像
7XXXX 0LLLL 8YYYY 0LLLL 7XXXX 8YYYY 9ZZZZ 0LLLL
这样的组
我正在尝试使用 Boost::regex 库实现我的目标。
我想拆分这些组并将它们放入数组或向量中。现在我正试图cout
它们。
我正在尝试这样做,但我只能在 7,8,9,0 组中的每一个组中获得完整的字符串匹配或最后一个匹配,但不能像这样的字符串 7XXXX 8YYYY 9ZZZZ 0LLLL
const char* pat = "(([[:space:]]+7[0-9]{4}){0,1}([[:space:]]+8[0-9]{4}){0,1}([[:space:]]+9[0-9]{4}){0,1}([[:space:]]+0[0-9]{4}){0,1})+";;
boost::regex reg(pat);
boost::smatch match;
string example= "71122 85451 75415 01102 75555 82133 91341 02134";
const int subgroups[] = {0,1,2,3,4,5,6};
boost::sregex_token_iterator i(example.begin(), example.end(), reg, subgroups);
boost::sregex_token_iterator j;
while (i != j)
{
cout << "Match: " << *i++ << endl;
}
示例输出:
Match: 71122 85451 75415 01102 75555 82133 91341 02134
<A bunch of empty "Match:" rows>
Match: 75555
Match: 82133
Match: 91341
Match: 02134
<A bunch of empty "Match:" rows>
但我想这样得到它:
71122 85451
75415 01102
75555 82133 91341 02134
我知道我做错了,不能想出一些好东西使用正则表达式来做我想做的事:(为什么我不能使用括号获取所有递归匹配?
编辑:由于我第一次完全误解了,所以我将替换整个答案。我沿着这些思路思考:
const char* pat = "[[:space:]]+((7[0-9]{4})?([[:space:]]+8[0-9]{4})?([[:space:]]+9[0-9]{4})?([[:space:]]+0[0-9]{4})?)";
boost::regex reg(pat);
boost::smatch match;
// v-- extra space here to make the match easier.
std::string example= " 71122 85451 75415 01102 75555 82133 91341 02134";
boost::sregex_token_iterator i(example.begin(), example.end(), reg, 1);
boost::sregex_token_iterator j;
while (i != j)
{
std::cout << "Match: " << *i++ << std::endl;
}
如果无法修改字符串,则解决空匹配问题的解决方法是
const char* pat = "((7[0-9]{4})?([[:space:]]+8[0-9]{4})?([[:space:]]+9[0-9]{4})?([[:space:]]+0[0-9]{4})?)";
boost::regex reg(pat);
boost::smatch match;
std::string example= "71122 85451 75415 01102 75555 82133 91341 02134";
boost::sregex_token_iterator i(example.begin(), example.end(), reg, 1);
boost::sregex_token_iterator j;
while (i != j)
{
if(i->length() != 0) {
std::cout << "Match: " << *i << std::endl;
}
++i;
}
尽管在这种情况下,使用 regex_iterator
而不是 regex_token_iterator
可以说更好:
// No need for outer spaces anymore
const char* pat = "(7[0-9]{4})?([[:space:]]+8[0-9]{4})?([[:space:]]+9[0-9]{4})?([[:space:]]+0[0-9]{4})?";
boost::sregex_iterator i(example.begin(), example.end(), reg);
boost::sregex_iterator j;
// Rest the same.
我想
我会在这里手动滚动解析器。为了敏捷性,如何解析
精神- 它直接解析为序列向量。
- 处理空格没有问题。 语法
- 以声明方式描述,其语法有点类似于正则表达式,但与C++语言的联系要强得多。
它非常清楚地表达了意图:序列是按预期顺序排列的项目的任意组合 - 只要结果至少有一个项目
seq_ = -item_('7') >> -item_('8') >> -item_('9') >> -item_('0');
其中
item_
解析以指示数字开头的任何整数:item_ = &char_(_r1) >> uint_;
在解析器中,我们使用
*seq
解析任意数量的序列,这就是为什么我们添加了一个检查,检查每个匹配的序列不为空(否则我们可以得到一个无限循环,匹配在同一输入位置的空序列(eps(phx::size(_val) > 0) // require 1 element at least
请注意调试是如何内置的(通过取消注释第一行来启用它(。
请注意,通过省略前导字符从结果中排除前导数字是多么微不足道: 查看 Coliru 上的替代版本:
item_ = omit[char_(_r1)] >> uint_;
测试程序输出:
Parsing: 71122 85451 75415 01102 75555 82133 91341 02134
Parsed: 3 sequences
seq: 71122 85451
seq: 75415 1102
seq: 75555 82133 91341 2134
住在科里鲁
//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
using data = std::vector<std::vector<unsigned> >;
template <typename It, typename Skipper = qi::space_type>
struct grammar : qi::grammar<It, data(), Skipper> {
grammar() : grammar::base_type(start) {
using namespace qi;
start = *seq_;
seq_ = -item_('7') >> -item_('8') >> -item_('9') >> -item_('0')
>> eps(phx::size(_val) > 0)
;
item_ = &char_(_r1) >> uint_;
BOOST_SPIRIT_DEBUG_NODES((start)(item_)(seq_))
}
private:
qi::rule<It, unsigned(char), Skipper> item_;
qi::rule<It, std::vector<unsigned>(), Skipper> seq_;
qi::rule<It, data(), Skipper> start;
};
int main() {
for (std::string const input : {
"71122 85451 75415 01102 75555 82133 91341 02134"
})
{
using It = std::string::const_iterator;
grammar<It> p;
auto f(input.begin()), l(input.end());
data parsed;
bool ok = qi::phrase_parse(f,l,p,qi::space,parsed);
std::cout << "Parsing: " << input << "n";
if (ok) {
std::cout << "Parsed: " << parsed.size() << " sequencesn";
for(auto& seq : parsed)
std::copy(seq.begin(), seq.end(), std::ostream_iterator<unsigned>(std::cout << "nseq:t", " "));
std::cout << "n";
} else {
std::cout << "Parsed failedn";
}
if (f!=l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'n";
}
}
相关文章:
- FindPackageHandleStandardArgs.cmake:137 的 CMake 错误(消息):找不到 Boost (缺少:正则表达式)(找到合适的版本"1.72.0",
- 为什么 Boost:正则表达式没有按预期找到所有结果?
- 使用 boost::regex 从目录中获取带有一些正则表达式的文件名称时出现意外输出
- 使用 boost::regex (c++) 比较两个正则表达式
- 我的 Boost 正则表达式与任何内容都不匹配
- 使用boost正则表达式时出现shared_ptr错误
- Boost正则表达式:链接时未定义的引用
- 如何使用perl样式内存正则表达式与Boost库匹配
- 如何获得与 C++11 或 Boost 匹配的正则表达式长度
- 递归匹配与 boost 正则表达式库
- 提高Boost正则表达式的速度或在C++中使用PCRE
- boost正则表达式中的命名捕获/组列表
- 使用Boost替换正则表达式
- 关于正则表达式与Boost的逻辑AND和OR匹配的说明
- 将 C++11 正则表达式与 gcc 4.8.2 一起使用时会出现奇怪的结果(但适用于 Boost 正则表达式)
- 使用 Boost 的 C++ 中的正则表达式
- Boost::qt Creator中的正则表达式
- 如何使 Boost.Spirit.Lex 令牌值成为匹配序列的子字符串(最好通过正则表达式匹配组)
- Boost.Test 使用正则表达式测试文件内容
- 使用 Boost::regex 进行正则表达式组匹配