从 boost spirit x3 解析器返回的向量中的空字符串
Empty strings in vector returned from boost spirit x3 parser
我想检查所有枚举的文件(这只是一个 MCVE,所以没有什么复杂的)并且枚举的名称应该存储在 std::vector
我这样构建我的解析器:
auto const any = x3::rule<class any_id, const x3::unused_type>{"any"}
= ~x3::space;
auto const identifier = x3::rule<class identifier_id, std::string>{"identifier"}
= x3::lexeme[x3::char_("A-Za-z_") >> *x3::char_("A-Za-z_0-9")];
auto const enum_finder = x3::rule<class enum_finder_id, std::vector<std::string>>{"enum_finder"}
= *(("enum" >> identifier) | any);
当我尝试将带有此 enum_finder
的字符串解析为 std::vector
时,std::vector
还包含大量空字符串。
为什么这个解析器也将空字符串解析到向量中?
我假设您想从忽略空格的自由格式文本中解析 "enum "。
你真正想要的是让("enum" >> identifier | any)
合成一个optional<string>
。可悲的是,你得到的是 variant<string, unused_type>
或类似的东西。
用 x3::omit[any]
包裹 any
时也会发生同样的情况 - 它仍然是相同的 unused_type。
B 计划:既然你真的只是解析由 "anything" 分隔的重复枚举 ID,为什么不使用列表运算符:
("enum" >> identifier) % any
这有点管用。现在进行一些调整:让我们避免一个字符一个字符地吃掉 "any"。事实上,我们可能只使用整个空格分隔的单词:(注意 +~space
等价于 +graph
):
auto const any = x3::rule<class any_id>{"any"}
= x3::lexeme [+x3::graph];
接下来,为了允许连续接受多个虚假词,有一个技巧可以使列表的主题解析器成为可选的:
-("enum" >> identifier) % any;
解析正确。查看完整演示:
演示
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
namespace parser {
using namespace x3;
auto any = lexeme [+~space];
auto identifier = lexeme [char_("A-Za-z_") >> *char_("A-Za-z_0-9")];
auto enum_finder = -("enum" >> identifier) % any;
}
#include <iostream>
int main() {
for (std::string input : {
"",
" ",
"bogus",
"enum one",
"enum one enum two",
"enum one bogus bogus more bogus enum two !@#!@#Yay",
})
{
auto f = input.begin(), l = input.end();
std::cout << "------------ parsing '" << input << "'\n";
std::vector<std::string> data;
if (phrase_parse(f, l, parser::enum_finder, x3::space, data))
{
std::cout << "parsed " << data.size() << " elements:\n";
for (auto& el : data)
std::cout << "\t" << el << "\n";
} else {
std::cout << "Parse failure\n";
}
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
打印:
------------ parsing ''
parsed 0 elements:
------------ parsing ' '
parsed 0 elements:
------------ parsing 'bogus'
parsed 0 elements:
------------ parsing 'enum one'
parsed 1 elements:
one
------------ parsing 'enum one enum two'
parsed 1 elements:
one
------------ parsing 'enum one bogus bogus more bogus enum two !@#!@#Yay'
parsed 2 elements:
one
two
我想检查所有枚举的文件(这只是一个 MCVE,所以没有什么复杂的)并且枚举的名称应该存储在 std::vector
我这样构建我的解析器:
auto const any = x3::rule<class any_id, const x3::unused_type>{"any"}
= ~x3::space;
auto const identifier = x3::rule<class identifier_id, std::string>{"identifier"}
= x3::lexeme[x3::char_("A-Za-z_") >> *x3::char_("A-Za-z_0-9")];
auto const enum_finder = x3::rule<class enum_finder_id, std::vector<std::string>>{"enum_finder"}
= *(("enum" >> identifier) | any);
当我尝试将带有此 enum_finder
的字符串解析为 std::vector
时,std::vector
还包含大量空字符串。
为什么这个解析器也将空字符串解析到向量中?
我假设您想从忽略空格的自由格式文本中解析 "enum "。
你真正想要的是让("enum" >> identifier | any)
合成一个optional<string>
。可悲的是,你得到的是 variant<string, unused_type>
或类似的东西。
用 x3::omit[any]
包裹 any
时也会发生同样的情况 - 它仍然是相同的 unused_type。
B 计划:既然你真的只是解析由 "anything" 分隔的重复枚举 ID,为什么不使用列表运算符:
("enum" >> identifier) % any
这有点管用。现在进行一些调整:让我们避免一个字符一个字符地吃掉 "any"。事实上,我们可能只使用整个空格分隔的单词:(注意 +~space
等价于 +graph
):
auto const any = x3::rule<class any_id>{"any"}
= x3::lexeme [+x3::graph];
接下来,为了允许连续接受多个虚假词,有一个技巧可以使列表的主题解析器成为可选的:
-("enum" >> identifier) % any;
解析正确。查看完整演示:
演示
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
namespace parser {
using namespace x3;
auto any = lexeme [+~space];
auto identifier = lexeme [char_("A-Za-z_") >> *char_("A-Za-z_0-9")];
auto enum_finder = -("enum" >> identifier) % any;
}
#include <iostream>
int main() {
for (std::string input : {
"",
" ",
"bogus",
"enum one",
"enum one enum two",
"enum one bogus bogus more bogus enum two !@#!@#Yay",
})
{
auto f = input.begin(), l = input.end();
std::cout << "------------ parsing '" << input << "'\n";
std::vector<std::string> data;
if (phrase_parse(f, l, parser::enum_finder, x3::space, data))
{
std::cout << "parsed " << data.size() << " elements:\n";
for (auto& el : data)
std::cout << "\t" << el << "\n";
} else {
std::cout << "Parse failure\n";
}
if (f!=l)
std::cout << "Remaining unparsed: '" << std::string(f,l) << "'\n";
}
}
打印:
------------ parsing ''
parsed 0 elements:
------------ parsing ' '
parsed 0 elements:
------------ parsing 'bogus'
parsed 0 elements:
------------ parsing 'enum one'
parsed 1 elements:
one
------------ parsing 'enum one enum two'
parsed 1 elements:
one
------------ parsing 'enum one bogus bogus more bogus enum two !@#!@#Yay'
parsed 2 elements:
one
two