如何在 Boost Spirit 中跳过(不输出)令牌?
How to skip (not output) tokens in Boost Spirit?
我是 Boost Spirit 的新手。我一直无法找到一些简单事物的例子。例如,假设我有偶数个 space 分隔的整数。 (匹配 *(qi::int_ >> qi::int_)
。到目前为止一切顺利。)我只想将 even 保存到 std::vector<int>
。我已经尝试了各种方法,例如 *(qi::int_ >> qi::skip[qi::int_])
https://godbolt.org/z/KPToo3xh6 但它仍然记录每个 int,而不仅仅是偶数。
#include <stdexcept>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
// Example based off https://raw.githubusercontent.com/bingmann/2018-cpp-spirit-parsing/master/spirit1_simple.cpp:
// Helper to run a parser, check for errors, and capture the results.
template <typename Parser, typename Skipper, typename ... Args>
void PhraseParseOrDie(
const std::string& input, const Parser& p, const Skipper& s,
Args&& ... args)
{
std::string::const_iterator begin = input.begin(), end = input.end();
boost::spirit::qi::phrase_parse(begin, end, p, s, std::forward<Args>(args) ...);
if (begin != end) {
fmt::print("Unparseable: \"{}\"\n", std::string(begin, end));
}
}
void test(std::string input)
{
std::vector<int> out_int_list;
PhraseParseOrDie(
// input string
input,
// parser grammar
*(qi::int_ >> qi::skip[qi::int_]),
// skip parser
qi::space,
// output list
out_int_list);
fmt::print("test() parse result: {}\n", out_int_list);
}
int main(int argc, char* argv[])
{
test("12345 42 5 2");
return 0;
}
版画
test() parse result: [12345, 42, 5, 2]
您正在寻找 qi::omit[]
:
*(qi::int_ >> qi::omit[qi::int_])
请注意,您也可以通过声明不带 attribute-type 的规则来隐式省略某些内容(这使其绑定到 qi::unused_type
以实现静默兼容性)。
另请注意,如果您正在制作一个 临时的、草率的语法 来扫描较大文本中的某些“地标”,请考虑 spirit::repository::qi::seek
这可以明显更快,更具表现力。
最后,请注意 Spirit X3 附带了一个类似的开箱即用的 seek[]
指令。
简化的演示
简化很多:https://godbolt.org/z/EY4KdxYv9
#include <fmt/ranges.h>
#include <boost/spirit/include/qi.hpp>
// Helper to run a parser, check for errors, and capture the results.
void test(std::string const& input)
{
std::vector<int> out_int_list;
namespace qi = boost::spirit::qi;
qi::parse(input.begin(), input.end(), //
qi::expect[ //
qi::skip(qi::space)[ //
*(qi::int_ >> qi::omit[qi::int_]) > qi::eoi]], //
out_int_list);
fmt::print("test() parse result: {}\n", out_int_list);
}
int main() { test("12345 42 5 2"); }
版画
test() parse result: [12345, 5]
但是等等
看到你的评论
// Parse a bracketed list of integers with spaces between symbols
你是认真的吗?因为这听起来更像是:
'[' > qi::auto_ % +qi::graph > ']'
现场观看:https://godbolt.org/z/eK6Thzqea
//#define BOOST_SPIRIT_DEBUG
#include <fmt/ranges.h>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_auto.hpp>
//#include <boost/fusion/adapted.hpp>
// Helper to run a parser, check for errors, and capture the results.
template <typename T> auto test(std::string const& input) {
std::vector<T> out;
using namespace boost::spirit::qi;
rule<std::string::const_iterator, T()> v = auto_;
BOOST_SPIRIT_DEBUG_NODE(v);
phrase_parse( //
input.begin(), input.end(), //
'[' > -v % lexeme[+(graph - ']')] > ']', //
space, out);
return out;
}
int main() {
fmt::print("ints: {}\n", test<int>("[12345 USD 5 PUT]"));
fmt::print("doubles: {}\n", test<double>("[ 1.2345 42 -inf 'hello' 3.1415 ]"));
}
版画
ints: [12345, 5]
doubles: [1.2345, -inf, 3.1415]
我是 Boost Spirit 的新手。我一直无法找到一些简单事物的例子。例如,假设我有偶数个 space 分隔的整数。 (匹配 *(qi::int_ >> qi::int_)
。到目前为止一切顺利。)我只想将 even 保存到 std::vector<int>
。我已经尝试了各种方法,例如 *(qi::int_ >> qi::skip[qi::int_])
https://godbolt.org/z/KPToo3xh6 但它仍然记录每个 int,而不仅仅是偶数。
#include <stdexcept>
#include <fmt/format.h>
#include <fmt/ranges.h>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
// Example based off https://raw.githubusercontent.com/bingmann/2018-cpp-spirit-parsing/master/spirit1_simple.cpp:
// Helper to run a parser, check for errors, and capture the results.
template <typename Parser, typename Skipper, typename ... Args>
void PhraseParseOrDie(
const std::string& input, const Parser& p, const Skipper& s,
Args&& ... args)
{
std::string::const_iterator begin = input.begin(), end = input.end();
boost::spirit::qi::phrase_parse(begin, end, p, s, std::forward<Args>(args) ...);
if (begin != end) {
fmt::print("Unparseable: \"{}\"\n", std::string(begin, end));
}
}
void test(std::string input)
{
std::vector<int> out_int_list;
PhraseParseOrDie(
// input string
input,
// parser grammar
*(qi::int_ >> qi::skip[qi::int_]),
// skip parser
qi::space,
// output list
out_int_list);
fmt::print("test() parse result: {}\n", out_int_list);
}
int main(int argc, char* argv[])
{
test("12345 42 5 2");
return 0;
}
版画
test() parse result: [12345, 42, 5, 2]
您正在寻找 qi::omit[]
:
*(qi::int_ >> qi::omit[qi::int_])
请注意,您也可以通过声明不带 attribute-type 的规则来隐式省略某些内容(这使其绑定到 qi::unused_type
以实现静默兼容性)。
另请注意,如果您正在制作一个 临时的、草率的语法 来扫描较大文本中的某些“地标”,请考虑 spirit::repository::qi::seek
这可以明显更快,更具表现力。
最后,请注意 Spirit X3 附带了一个类似的开箱即用的 seek[]
指令。
简化的演示
简化很多:https://godbolt.org/z/EY4KdxYv9
#include <fmt/ranges.h>
#include <boost/spirit/include/qi.hpp>
// Helper to run a parser, check for errors, and capture the results.
void test(std::string const& input)
{
std::vector<int> out_int_list;
namespace qi = boost::spirit::qi;
qi::parse(input.begin(), input.end(), //
qi::expect[ //
qi::skip(qi::space)[ //
*(qi::int_ >> qi::omit[qi::int_]) > qi::eoi]], //
out_int_list);
fmt::print("test() parse result: {}\n", out_int_list);
}
int main() { test("12345 42 5 2"); }
版画
test() parse result: [12345, 5]
但是等等
看到你的评论
// Parse a bracketed list of integers with spaces between symbols
你是认真的吗?因为这听起来更像是:
'[' > qi::auto_ % +qi::graph > ']'
现场观看:https://godbolt.org/z/eK6Thzqea
//#define BOOST_SPIRIT_DEBUG
#include <fmt/ranges.h>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/qi_auto.hpp>
//#include <boost/fusion/adapted.hpp>
// Helper to run a parser, check for errors, and capture the results.
template <typename T> auto test(std::string const& input) {
std::vector<T> out;
using namespace boost::spirit::qi;
rule<std::string::const_iterator, T()> v = auto_;
BOOST_SPIRIT_DEBUG_NODE(v);
phrase_parse( //
input.begin(), input.end(), //
'[' > -v % lexeme[+(graph - ']')] > ']', //
space, out);
return out;
}
int main() {
fmt::print("ints: {}\n", test<int>("[12345 USD 5 PUT]"));
fmt::print("doubles: {}\n", test<double>("[ 1.2345 42 -inf 'hello' 3.1415 ]"));
}
版画
ints: [12345, 5]
doubles: [1.2345, -inf, 3.1415]