正在跳过规则中的强制性 boost::spirit::qi::attr(0)
Mandatory boost::spirit::qi::attr(0) in rule is beeing skipped
我正在努力实施一条规则,其中所有元素都是各种列表的一部分。元素的类型不能混合。
这是有效的:1/1/ 2/2/ 3/3/
并且应该使用强制性零进行解析,例如 1/1/0 2/2/0 3/3/0
下面的示例包含一个我认为创建属性的规则。它适用于 int_/0/int_
版本,但不适用于 int_/int_/0
版本。
事实上,属性零似乎被完全跳过,而是使用下一个 int_(数字 2)。
这是一些注释输出:
这是一个更长的示例,包括所有使用的测试和规则:
#pragma once
#include <string>
#include <vector>
#include <regex>
#include <list>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/spirit/include/qi.hpp>
typedef struct { int a; int b; int c; } int_triplet;
typedef struct std::vector<int_triplet> int_triplet_vector;
BOOST_FUSION_ADAPT_STRUCT(int_triplet, a, b, c)
namespace qi = boost::spirit::qi;
typedef std::string::iterator Iterator;
typedef qi::rule<Iterator> skipper_rule;
typedef qi::rule<Iterator> line_rule;
typedef qi::rule<Iterator, std::string(), skipper_rule> string_rule;
typedef qi::rule<Iterator, int_triplet(), skipper_rule> int_triplet_rule;
typedef qi::rule<Iterator, int_triplet_vector(), skipper_rule> int_triplet_vector_rule;
line_rule endofline = qi::lit("\r\n") | qi::lit("\n\r") | qi::lit('\n');
skipper_rule skip = qi::lit(' ') | qi::lit('\t') | qi::lit('\f') | qi::lit('\v') | (qi::lit('\') >> endofline);
int_triplet_rule faceIndex_v_0_vn = qi::int_ >> qi::lit('/') >> qi::attr((int)0) >> qi::lit('/') >> qi::int_;
//int_triplet_rule faceIndex_v_vt__0 = qi::int_ >> qi::lit('/') >> qi::int_ >> qi::lit('/') >> qi::attr(0);
int_triplet_rule faceIndex_v_vt_0 = qi::lexeme[qi::int_ >> qi::lit('/') >> qi::int_ >> qi::lit('/') >> ((!qi::int_) | qi::attr((int)0))];
int_triplet_rule faceIndex_v_vt_vn = qi::int_ >> qi::lit('/') >> qi::int_ >> qi::lit('/') >> qi::int_;
int_triplet_vector_rule f = 'f' >> (+faceIndex_v_vt_vn | +faceIndex_v_0_vn | +faceIndex_v_vt_0) >> endofline;
//int_triplet_vector_rule f = 'f' >> (+faceIndex_v_vt_vn | +faceIndex_v__0_vn | +faceIndex_v_vt__0 ) >> endofline;
//int_triplet_vector_rule f = 'f' >> *( faceIndex_v__0_vn | faceIndex_v_vt__0 | faceIndex_v_vt_vn ) >> endofline;
std::string ReplaceTRNVF(std::string str)
{
std::string strmod = str;
std::list<std::string> rs = { "\t", "\r", "\n", "\v", "\f" };
for(auto r : rs)
strmod = std::regex_replace(strmod, std::regex(r), r);
return strmod;
}
void CHECK(std::string::iterator & it, std::string::iterator & end)
{
BOOST_CHECK_MESSAGE(it == end, ReplaceTRNVF((std::string)"Remaining:'" + std::string(it, end) + "'"));
}
void CHECK(int_triplet &expected, int_triplet &actual)
{
BOOST_CHECK_EQUAL(expected.a, actual.a);
BOOST_CHECK_EQUAL(expected.b, actual.b);
BOOST_CHECK_EQUAL(expected.c, actual.c);
}
void CHECK(int_triplet_vector &expected, int_triplet_vector &actual)
{
BOOST_CHECK_EQUAL(expected.size(), actual.size());
for (size_t n = 0; n < expected.size() && n < actual.size(); ++n)
CHECK(expected[n], actual[n]);
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Pass)
{
std::map<std::string, int_triplet_vector> data;
data["f 1/1/1 2/2/2 3/3/3 4/4/4\r\n"] = int_triplet_vector{ { 1, 1, 1 },{ 2, 2, 2 },{ 3, 3, 3 },{ 4, 4, 4 } };
data["f 1//1 2//2 3//3 4//4\r\n"] = int_triplet_vector{ { 1, 0, 1 },{ 2, 0, 2 },{ 3, 0, 3 },{ 4, 0, 4 } };
data["f 1/1/ 2/2/ 3/3/ 4/4/\r\n"] = int_triplet_vector{ { 1, 1, 0 },{ 2, 2, 0 },{ 3, 3, 0 },{ 4, 4, 0 } };
for (auto kvp : data)
{
int_triplet_vector result;
std::string test = kvp.first;
auto it = test.begin();
std::cout << ReplaceTRNVF("Test: " + test) << std::endl;
BOOST_CHECK(true == qi::phrase_parse(it, test.end(), f, skip, result));
CHECK(it, test.end());
CHECK(kvp.second, result);
}
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Fail)
{
std::list<std::string> data =
{
"f 1/1/1 2/2/2 3//3 4//4\r\n",
"f 1/1/ 2/2/ 3/3/ 4/4/4\r\n",
};
for (auto t : data)
{
int_triplet_vector result;
std::string test = t;
std::cout << ReplaceTRNVF("Test: " + test) << std::endl;
auto it = test.begin();
BOOST_CHECK(false == qi::phrase_parse(it, test.end(), f, skip, result));
}
}
如何使属性不沉没,以便它始终用于填充结构。
最后,我花了太多时间清理一些代码。
问题可能出在 !int_ | attr(0)
。因为,首先说"either you don't see another int, or you use the implied 0
"。我想这正是你不想说的。
Note: _postive lookahead would be &int_
- but even then that would not be what you wanted, because then you would want to actually parse it, and &int_ >> int_
is very much equivalent to int_
.
此外,总的来说,我没有看到使用船长使 tiplet 规则复杂化的原因(任何示例三元组中都没有空格;此外,允许它们确实会使语法含糊不清,因为不会判断给定整数是前一个三元组的尾数,还是下一个三元组的前导数的方法。)
从实际的三胞胎中移除船长,消除痛苦:
using namespace qi;
skip_ = char_(" \t\f\v") | '\' >> eol;
t1 = int_ >> '/' >> int_ >> '/' >> int_;
t2 = int_ >> '/' >> attr(0) >> '/' >> int_;
t3 = int_ >> '/' >> int_ >> '/' >> attr(0);
triplets = +t1 | +t2 | +t3;
f = 'f' >> triplets >> eol;
start = skip(copy(skip_)) [ f ];
这是我转换的最终结果:
//#define BOOST_SPIRIT_DEBUG
//#pragma once
#include <string>
#include <vector>
#include <regex>
#include <list>
#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>
#include <boost/spirit/include/qi.hpp>
namespace std {
template <typename T>
ostream& operator<<(ostream& os, vector<T> const& v) {
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
return os;
}
}
struct int_triplet {
int a;
int b;
int c;
bool operator==(int_triplet const& other) const {
return (a == other.a)
&& (b == other.b)
&& (c == other.c);
}
friend std::ostream& operator<<(std::ostream& os, int_triplet const& t) {
return os << t.a << '/' << t.b << '/' << t.c;
}
};
typedef std::vector<int_triplet> int_triplet_vector;
BOOST_FUSION_ADAPT_STRUCT(int_triplet, a, b, c)
namespace parsing {
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct grammar : qi::grammar<Iterator, int_triplet_vector()> {
grammar() : grammar::base_type(start) {
using namespace qi;
skip_ = char_(" \t\f\v") | '\' >> eol;
t1 = int_ >> '/' >> int_ >> '/' >> int_;
t2 = int_ >> '/' >> attr(0) >> '/' >> int_;
t3 = int_ >> '/' >> int_ >> '/' >> attr(0);
triplets = +t1 | +t2 | +t3;
f = 'f' >> triplets >> eol;
start = skip(copy(skip_)) [ f ];
BOOST_SPIRIT_DEBUG_NODES((skip_)(t1)(t2)(t3)(triplets)(f)(start))
}
private:
qi::rule<Iterator, int_triplet_vector()> start;
typedef qi::rule<Iterator> Skipper;
Skipper skip_;
qi::rule<Iterator, int_triplet()> t1, t2, t3;
qi::rule<Iterator, int_triplet_vector(), Skipper> f, triplets;
};
static grammar<std::string::const_iterator> const f {};
}
std::string escape(std::string str) {
std::list<std::string> rs = { "\t", "\r", "\n", "\v", "\f" };
for (auto r : rs)
str = std::regex_replace(str, std::regex(r), r);
return str;
}
void CHECK(std::string::const_iterator it, std::string::const_iterator end) {
BOOST_CHECK_MESSAGE(it == end, escape((std::string) "Remaining:'" + std::string(it, end) + "'"));
}
void CHECK(int_triplet const&expected, int_triplet const&actual) {
BOOST_CHECK_EQUAL(expected, actual);
}
void CHECK(int_triplet_vector const&expected, int_triplet_vector const&actual) {
BOOST_CHECK_EQUAL(expected.size(), actual.size());
for (size_t n = 0; n < expected.size() && n < actual.size(); ++n)
CHECK(expected[n], actual[n]);
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Pass) {
std::map<std::string, int_triplet_vector> const data {
{"f 1/1/1 2/2/2 3/3/3 4/4/4\r\n", int_triplet_vector{ { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 }, { 4, 4, 4 } }},
{"f 1//1 2//2 3//3 4//4\r\n" , int_triplet_vector{ { 1, 0, 1 }, { 2, 0, 2 }, { 3, 0, 3 }, { 4, 0, 4 } }},
{"f 1/1/ 2/2/ 3/3/ 4/4/\r\n" , int_triplet_vector{ { 1, 1, 0 }, { 2, 2, 0 }, { 3, 3, 0 }, { 4, 4, 0 } }},
};
for (auto const& kvp : data) {
auto& test = kvp.first;
std::cout << "Test: " << escape(test) << std::endl;
auto it = test.begin();
int_triplet_vector result;
BOOST_CHECK(true == parse(it, test.end(), parsing::f, result));
CHECK(it, test.cend());
CHECK(kvp.second, result);
}
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Fail) {
std::list<std::string> const data = {
"f 1/1/1 2/2/2 3//3 4//4\r\n", "f 1/1/ 2/2/ 3/3/ 4/4/4\r\n",
};
for (std::string const& t : data) {
int_triplet_vector result;
std::cout << "Test: " << escape(t) << std::endl;
auto it = t.begin();
BOOST_CHECK(false == parse(it, t.end(), parsing::f, result));
}
}
输出:
Running 2 test cases...
Test: f 1//1 2//2 3//3 4//4\r\n
Test: f 1/1/ 2/2/ 3/3/ 4/4/\r\n
Test: f 1/1/1 2/2/2 3/3/3 4/4/4\r\n
Test: f 1/1/1 2/2/2 3//3 4//4\r\n
Test: f 1/1/ 2/2/ 3/3/ 4/4/4\r\n
*** No errors detected
(当然是在禁用调试信息的情况下)
我正在努力实施一条规则,其中所有元素都是各种列表的一部分。元素的类型不能混合。
这是有效的:1/1/ 2/2/ 3/3/
并且应该使用强制性零进行解析,例如 1/1/0 2/2/0 3/3/0
下面的示例包含一个我认为创建属性的规则。它适用于 int_/0/int_
版本,但不适用于 int_/int_/0
版本。
事实上,属性零似乎被完全跳过,而是使用下一个 int_(数字 2)。
这是一些注释输出:
这是一个更长的示例,包括所有使用的测试和规则:
#pragma once
#include <string>
#include <vector>
#include <regex>
#include <list>
#define BOOST_TEST_MAIN
#include <boost/test/unit_test.hpp>
#include <boost/spirit/include/qi.hpp>
typedef struct { int a; int b; int c; } int_triplet;
typedef struct std::vector<int_triplet> int_triplet_vector;
BOOST_FUSION_ADAPT_STRUCT(int_triplet, a, b, c)
namespace qi = boost::spirit::qi;
typedef std::string::iterator Iterator;
typedef qi::rule<Iterator> skipper_rule;
typedef qi::rule<Iterator> line_rule;
typedef qi::rule<Iterator, std::string(), skipper_rule> string_rule;
typedef qi::rule<Iterator, int_triplet(), skipper_rule> int_triplet_rule;
typedef qi::rule<Iterator, int_triplet_vector(), skipper_rule> int_triplet_vector_rule;
line_rule endofline = qi::lit("\r\n") | qi::lit("\n\r") | qi::lit('\n');
skipper_rule skip = qi::lit(' ') | qi::lit('\t') | qi::lit('\f') | qi::lit('\v') | (qi::lit('\') >> endofline);
int_triplet_rule faceIndex_v_0_vn = qi::int_ >> qi::lit('/') >> qi::attr((int)0) >> qi::lit('/') >> qi::int_;
//int_triplet_rule faceIndex_v_vt__0 = qi::int_ >> qi::lit('/') >> qi::int_ >> qi::lit('/') >> qi::attr(0);
int_triplet_rule faceIndex_v_vt_0 = qi::lexeme[qi::int_ >> qi::lit('/') >> qi::int_ >> qi::lit('/') >> ((!qi::int_) | qi::attr((int)0))];
int_triplet_rule faceIndex_v_vt_vn = qi::int_ >> qi::lit('/') >> qi::int_ >> qi::lit('/') >> qi::int_;
int_triplet_vector_rule f = 'f' >> (+faceIndex_v_vt_vn | +faceIndex_v_0_vn | +faceIndex_v_vt_0) >> endofline;
//int_triplet_vector_rule f = 'f' >> (+faceIndex_v_vt_vn | +faceIndex_v__0_vn | +faceIndex_v_vt__0 ) >> endofline;
//int_triplet_vector_rule f = 'f' >> *( faceIndex_v__0_vn | faceIndex_v_vt__0 | faceIndex_v_vt_vn ) >> endofline;
std::string ReplaceTRNVF(std::string str)
{
std::string strmod = str;
std::list<std::string> rs = { "\t", "\r", "\n", "\v", "\f" };
for(auto r : rs)
strmod = std::regex_replace(strmod, std::regex(r), r);
return strmod;
}
void CHECK(std::string::iterator & it, std::string::iterator & end)
{
BOOST_CHECK_MESSAGE(it == end, ReplaceTRNVF((std::string)"Remaining:'" + std::string(it, end) + "'"));
}
void CHECK(int_triplet &expected, int_triplet &actual)
{
BOOST_CHECK_EQUAL(expected.a, actual.a);
BOOST_CHECK_EQUAL(expected.b, actual.b);
BOOST_CHECK_EQUAL(expected.c, actual.c);
}
void CHECK(int_triplet_vector &expected, int_triplet_vector &actual)
{
BOOST_CHECK_EQUAL(expected.size(), actual.size());
for (size_t n = 0; n < expected.size() && n < actual.size(); ++n)
CHECK(expected[n], actual[n]);
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Pass)
{
std::map<std::string, int_triplet_vector> data;
data["f 1/1/1 2/2/2 3/3/3 4/4/4\r\n"] = int_triplet_vector{ { 1, 1, 1 },{ 2, 2, 2 },{ 3, 3, 3 },{ 4, 4, 4 } };
data["f 1//1 2//2 3//3 4//4\r\n"] = int_triplet_vector{ { 1, 0, 1 },{ 2, 0, 2 },{ 3, 0, 3 },{ 4, 0, 4 } };
data["f 1/1/ 2/2/ 3/3/ 4/4/\r\n"] = int_triplet_vector{ { 1, 1, 0 },{ 2, 2, 0 },{ 3, 3, 0 },{ 4, 4, 0 } };
for (auto kvp : data)
{
int_triplet_vector result;
std::string test = kvp.first;
auto it = test.begin();
std::cout << ReplaceTRNVF("Test: " + test) << std::endl;
BOOST_CHECK(true == qi::phrase_parse(it, test.end(), f, skip, result));
CHECK(it, test.end());
CHECK(kvp.second, result);
}
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Fail)
{
std::list<std::string> data =
{
"f 1/1/1 2/2/2 3//3 4//4\r\n",
"f 1/1/ 2/2/ 3/3/ 4/4/4\r\n",
};
for (auto t : data)
{
int_triplet_vector result;
std::string test = t;
std::cout << ReplaceTRNVF("Test: " + test) << std::endl;
auto it = test.begin();
BOOST_CHECK(false == qi::phrase_parse(it, test.end(), f, skip, result));
}
}
如何使属性不沉没,以便它始终用于填充结构。
最后,我花了太多时间清理一些代码。
问题可能出在 !int_ | attr(0)
。因为,首先说"either you don't see another int, or you use the implied 0
"。我想这正是你不想说的。
Note: _postive lookahead would be
&int_
- but even then that would not be what you wanted, because then you would want to actually parse it, and&int_ >> int_
is very much equivalent toint_
.
此外,总的来说,我没有看到使用船长使 tiplet 规则复杂化的原因(任何示例三元组中都没有空格;此外,允许它们确实会使语法含糊不清,因为不会判断给定整数是前一个三元组的尾数,还是下一个三元组的前导数的方法。)
从实际的三胞胎中移除船长,消除痛苦:
using namespace qi;
skip_ = char_(" \t\f\v") | '\' >> eol;
t1 = int_ >> '/' >> int_ >> '/' >> int_;
t2 = int_ >> '/' >> attr(0) >> '/' >> int_;
t3 = int_ >> '/' >> int_ >> '/' >> attr(0);
triplets = +t1 | +t2 | +t3;
f = 'f' >> triplets >> eol;
start = skip(copy(skip_)) [ f ];
这是我转换的最终结果:
//#define BOOST_SPIRIT_DEBUG
//#pragma once
#include <string>
#include <vector>
#include <regex>
#include <list>
#define BOOST_TEST_MAIN
#include <boost/test/included/unit_test.hpp>
#include <boost/spirit/include/qi.hpp>
namespace std {
template <typename T>
ostream& operator<<(ostream& os, vector<T> const& v) {
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
return os;
}
}
struct int_triplet {
int a;
int b;
int c;
bool operator==(int_triplet const& other) const {
return (a == other.a)
&& (b == other.b)
&& (c == other.c);
}
friend std::ostream& operator<<(std::ostream& os, int_triplet const& t) {
return os << t.a << '/' << t.b << '/' << t.c;
}
};
typedef std::vector<int_triplet> int_triplet_vector;
BOOST_FUSION_ADAPT_STRUCT(int_triplet, a, b, c)
namespace parsing {
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct grammar : qi::grammar<Iterator, int_triplet_vector()> {
grammar() : grammar::base_type(start) {
using namespace qi;
skip_ = char_(" \t\f\v") | '\' >> eol;
t1 = int_ >> '/' >> int_ >> '/' >> int_;
t2 = int_ >> '/' >> attr(0) >> '/' >> int_;
t3 = int_ >> '/' >> int_ >> '/' >> attr(0);
triplets = +t1 | +t2 | +t3;
f = 'f' >> triplets >> eol;
start = skip(copy(skip_)) [ f ];
BOOST_SPIRIT_DEBUG_NODES((skip_)(t1)(t2)(t3)(triplets)(f)(start))
}
private:
qi::rule<Iterator, int_triplet_vector()> start;
typedef qi::rule<Iterator> Skipper;
Skipper skip_;
qi::rule<Iterator, int_triplet()> t1, t2, t3;
qi::rule<Iterator, int_triplet_vector(), Skipper> f, triplets;
};
static grammar<std::string::const_iterator> const f {};
}
std::string escape(std::string str) {
std::list<std::string> rs = { "\t", "\r", "\n", "\v", "\f" };
for (auto r : rs)
str = std::regex_replace(str, std::regex(r), r);
return str;
}
void CHECK(std::string::const_iterator it, std::string::const_iterator end) {
BOOST_CHECK_MESSAGE(it == end, escape((std::string) "Remaining:'" + std::string(it, end) + "'"));
}
void CHECK(int_triplet const&expected, int_triplet const&actual) {
BOOST_CHECK_EQUAL(expected, actual);
}
void CHECK(int_triplet_vector const&expected, int_triplet_vector const&actual) {
BOOST_CHECK_EQUAL(expected.size(), actual.size());
for (size_t n = 0; n < expected.size() && n < actual.size(); ++n)
CHECK(expected[n], actual[n]);
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Pass) {
std::map<std::string, int_triplet_vector> const data {
{"f 1/1/1 2/2/2 3/3/3 4/4/4\r\n", int_triplet_vector{ { 1, 1, 1 }, { 2, 2, 2 }, { 3, 3, 3 }, { 4, 4, 4 } }},
{"f 1//1 2//2 3//3 4//4\r\n" , int_triplet_vector{ { 1, 0, 1 }, { 2, 0, 2 }, { 3, 0, 3 }, { 4, 0, 4 } }},
{"f 1/1/ 2/2/ 3/3/ 4/4/\r\n" , int_triplet_vector{ { 1, 1, 0 }, { 2, 2, 0 }, { 3, 3, 0 }, { 4, 4, 0 } }},
};
for (auto const& kvp : data) {
auto& test = kvp.first;
std::cout << "Test: " << escape(test) << std::endl;
auto it = test.begin();
int_triplet_vector result;
BOOST_CHECK(true == parse(it, test.end(), parsing::f, result));
CHECK(it, test.cend());
CHECK(kvp.second, result);
}
}
BOOST_AUTO_TEST_CASE(Rules_FaceIndex_Fail) {
std::list<std::string> const data = {
"f 1/1/1 2/2/2 3//3 4//4\r\n", "f 1/1/ 2/2/ 3/3/ 4/4/4\r\n",
};
for (std::string const& t : data) {
int_triplet_vector result;
std::cout << "Test: " << escape(t) << std::endl;
auto it = t.begin();
BOOST_CHECK(false == parse(it, t.end(), parsing::f, result));
}
}
输出:
Running 2 test cases...
Test: f 1//1 2//2 3//3 4//4\r\n
Test: f 1/1/ 2/2/ 3/3/ 4/4/\r\n
Test: f 1/1/1 2/2/2 3/3/3 4/4/4\r\n
Test: f 1/1/1 2/2/2 3//3 4//4\r\n
Test: f 1/1/ 2/2/ 3/3/ 4/4/4\r\n
*** No errors detected
(当然是在禁用调试信息的情况下)