如何编写 boost::spirit::qi 解析器来执行“?”在正则表达式中吗?
How to write a boost::spirit::qi parser to do what '?' does in regex?
假设我们有一个正则表达式 "start:(?: ([0-9]{1,2}))? ([0-9].*)"。
它将匹配
std::string string1 = "start: 01 0ab";
和
std::string string2 = "start: 0ab";
我们也可以分别得到2个匹配的字符串。
我尝试使用 boost::spirit::qi 解析器来解析 string2 但无法匹配。
qi::rule<std::string::const_iterator, std::string()> rule1 = qi::repeat(1,2)[qi::digit];
qi::rule<std::string::const_iterator, std::string()> rule2 = qi::digit >> *qi::char_;
std::vector<std::string> attr;
auto it_begin = string2.begin();
auto it_end = string2.end();
if (qi::parse(
it_begin,
it_end,
qi::lit("start:")
>> -(qi::lit(" ") >> rule1)
>> qi::lit(" ") >> rule2
>> qi::eoi,
attr))
std::cout<<"match"<<std::endl;
else
std::cout<<"not match"<<std::endl;
我们当然可以使用前瞻运算符来检查规则 1 背后的内容,但是是否有更通用的方法来实现正则表达式运算符“?” ?谢谢!
我不确定期望有什么问题。对于其他不明确的规则,这是唯一的方法,因为 PEG 语法总是贪婪的。
但是,也许您没有找到最优雅的形式,因为您正在寻找一些东西 "better"。这就是我要做的。
我会使用船长来匹配空格¹:
if (qi::phrase_parse(it_begin, it_end,
"start:" >> -rule1 >> rule2 >> qi::eoi,
qi::space, attr))
规则仍然是词素的地方(因为没有船长声明):
qi::rule<It, std::string()> const
rule1 = qi::digit >> qi::digit >> &qi::space,
rule2 = qi::digit >> *qi::graph;
Note qi::graph
doesn't match whitespace, where *qi::char_
simply matches anything at all greedily.
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main() {
using It = std::string::const_iterator;
// implicitly lexemes (no skipper in rule declaration)
qi::rule<It, std::string()> const
rule1 = qi::digit >> qi::digit >> &qi::space,
rule2 = qi::digit >> *qi::graph;
for (std::string const input : { "start: 01 0ab", "start: 0ab", }) {
std::vector<std::string> attr;
auto it_begin = input.begin();
auto it_end = input.end();
if (qi::phrase_parse(it_begin, it_end, "start:" >> -rule1 >> rule2 >> qi::eoi, qi::space, attr))
std::cout << "match\n";
else
std::cout << "not match\n";
if (it_begin!=it_end)
std::cout<<"Remaining unparsed input: '" << std::string(it_begin, it_end) << "'\n";
}
}
版画
match
match
¹ 这假设 multiple/different 空白是可以的。如果换行不应算作空格,请使用 qi::blank
而不是 qi::space
假设我们有一个正则表达式 "start:(?: ([0-9]{1,2}))? ([0-9].*)"。
它将匹配
std::string string1 = "start: 01 0ab";
和
std::string string2 = "start: 0ab";
我们也可以分别得到2个匹配的字符串。
我尝试使用 boost::spirit::qi 解析器来解析 string2 但无法匹配。
qi::rule<std::string::const_iterator, std::string()> rule1 = qi::repeat(1,2)[qi::digit];
qi::rule<std::string::const_iterator, std::string()> rule2 = qi::digit >> *qi::char_;
std::vector<std::string> attr;
auto it_begin = string2.begin();
auto it_end = string2.end();
if (qi::parse(
it_begin,
it_end,
qi::lit("start:")
>> -(qi::lit(" ") >> rule1)
>> qi::lit(" ") >> rule2
>> qi::eoi,
attr))
std::cout<<"match"<<std::endl;
else
std::cout<<"not match"<<std::endl;
我们当然可以使用前瞻运算符来检查规则 1 背后的内容,但是是否有更通用的方法来实现正则表达式运算符“?” ?谢谢!
我不确定期望有什么问题。对于其他不明确的规则,这是唯一的方法,因为 PEG 语法总是贪婪的。
但是,也许您没有找到最优雅的形式,因为您正在寻找一些东西 "better"。这就是我要做的。
我会使用船长来匹配空格¹:
if (qi::phrase_parse(it_begin, it_end,
"start:" >> -rule1 >> rule2 >> qi::eoi,
qi::space, attr))
规则仍然是词素的地方(因为没有船长声明):
qi::rule<It, std::string()> const
rule1 = qi::digit >> qi::digit >> &qi::space,
rule2 = qi::digit >> *qi::graph;
Note
qi::graph
doesn't match whitespace, where*qi::char_
simply matches anything at all greedily.
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main() {
using It = std::string::const_iterator;
// implicitly lexemes (no skipper in rule declaration)
qi::rule<It, std::string()> const
rule1 = qi::digit >> qi::digit >> &qi::space,
rule2 = qi::digit >> *qi::graph;
for (std::string const input : { "start: 01 0ab", "start: 0ab", }) {
std::vector<std::string> attr;
auto it_begin = input.begin();
auto it_end = input.end();
if (qi::phrase_parse(it_begin, it_end, "start:" >> -rule1 >> rule2 >> qi::eoi, qi::space, attr))
std::cout << "match\n";
else
std::cout << "not match\n";
if (it_begin!=it_end)
std::cout<<"Remaining unparsed input: '" << std::string(it_begin, it_end) << "'\n";
}
}
版画
match
match
¹ 这假设 multiple/different 空白是可以的。如果换行不应算作空格,请使用 qi::blank
而不是 qi::space