Boost Spirit Parser 使用三个字符串的向量编译成一个结构,适应不工作
Boost Spirit Parser with a vector of three strings compiling into a struct, adapt not working
我是一名学生,需要使用 Boost-Library 用 C++ 编写解析器。
因此我在 QI 中写了一个语法,因为我需要解析成一个结构。到目前为止,一切都很好。
我会给你一些示例代码。我认为这比写下整个程序要容易。
说明:
所以首先我们获取一个 txt 文件并读取它,然后解析器遍历它,说 "Parsing is ok!" 并解析到结构中。我们的输出是控制台中的结构。
效果很好,现在来一些代码示例。在这里可以看到Boost Spirit QI中的语法:
subject %= lexeme[lit("Fach: ") >> +(char_("a-zA-Z")) >> lit("\n")]; //works!
dozent %= lexeme[lit("Dozent: ") >> +(char_("a-zA-Z")) >> lit("\n")];
date %= lexeme[lit("Datum: ") >> digit >> digit >> lit("-") >> digit >> digit >> lit("-") >> digit >> digit >> digit >> digit >> lit("\n")];
count %= lexeme[lit("Anzahl: ") >> +digit >> lit("\n")];
points %= lexeme[+digit >> lit("\t")];
mark %= lexeme[digit >> lit("\n")];
matnumber %= lexeme[(digit >> digit >> digit >> punct >> digit >> digit >> digit) >> lit("\t")];
student %= matnumber >> points >> mark;
start %= subject >> dozent >> date >> count >> student;
这很好用,student 的规则带来了一个问题,即我们有一个包含三个部分的元素。 Matnumber、Points 和 mark。你可以想象我的意思,这里是我们尝试解析的 TXT 文件:
Subject: Physics
Dozent: Wayne
Datum: 20-10-2014
Anzahl: 20
729.888 33 5
185.363 35 5
最后两行是rule student。而在 txt 文件中,我们不止这两行。
我们可以把这些行当作 "student" 我们用 typedef 在我们的结构中写了一个向量:
typedef boost::fusion::vector<string, string, string> student_t;
然后我们将在我们的结构中使用它:
struct klausur
{
string str_subject;
string str_dozent;
string str_date;
string count;
string matr_nr;
string points;
string mark;
string ende;
student_t student;
void ToString()
{
cout << "Struct.Fach: " << str_subject << endl;
cout << "Struct.Dozent: " << str_dozent << endl;
cout << "Struct.Datum: " << str_date << endl;
cout << "Struct.Anzahl: " << count << endl;
cout << "Struct.Mat_Nr: " << matr_nr << endl;
cout << "Struct.Punkte: " << points << endl;
cout << "Struct.Note: " << mark << endl;
cout << "Struct.Student<0>: " << vec::at_c<0>(student);
cout << "Struct.Student<1>: " << vec::at_c<1>(student);
cout << "Struct.Student<2>: " << vec::at_c<2>(student);
}
};
然后我们有这样的 BOOST_ADAPT_STRUCT:
BOOST_FUSION_ADAPT_STRUCT(
client::klausur,
(string, str_subject)
(string, str_dozent)
(string, str_date)
(string, count)
(string, matr_nr)
(string, points)
(string, mark)
(student_t, student)
)
你看我们下面有typedef。
然后我们在语法中有我们的规则。
qi::rule<Iterator, string(), ascii::space_type> subject;
qi::rule<Iterator, string(), ascii::space_type> dozent;
qi::rule<Iterator, string(), ascii::space_type> date;
qi::rule<Iterator, string(), ascii::space_type> count;
qi::rule<Iterator, string(), ascii::space_type> matnumber;
qi::rule<Iterator, string(), ascii::space_type> points;
qi::rule<Iterator, string(), ascii::space_type> mark;
qi::rule<Iterator, boost::fusion::vector<boost::fusion::vector<std::string, std::string, std::string> >()> student;
还有我们项目的最终问题……
我们不知道 qi:rule 需要哪种数据类型 BOOST_ADAPT... 可以正常工作。所有其他点都是字符串,但不知道如何实现我们创建的自己的向量。
所有其他规则都工作正常,稍后在结构中,只是向量出了问题。
有人对此有想法吗?如果您需要,我可以上传更多文件和代码片段,但我仍然认为这可能只是我看不到的一个小问题。我四处寻找许多提升主题,但没有找到合适的东西。
我必须补充一点,我只是一个初学者,所以也许我没有正确解释所有内容......是的。希望你能理解。我的英语也不是最好的...
提前感谢您的帮助。
威廉
Spirit 是一个解析器生成器。你似乎并没有真正解析任何东西(你只是 "extract" 字符序列,这更像是标记化)。
我会这样做:
- 使用正确的数据类型
- 使用
blank
跳过(不包括eol
)
- 将
eol
期望放在正确的位置
- 把词位放在正确的位置
- 使
date_t
成为自己的类型
- 使
student_t
成为自己的类型
- FIX 使用
std::vector<student_t>()
而不是 ~ fusion::vector<student_t>()
的规则(这是一个错误)
- 使用
operator<<
打印
- 使用
repeat(n) [ student >> eol ]
解析期望的学生行数
- 使用
qi::locals
实际将预期的学生人数传递给repeat()
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <iostream>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace vec = boost::fusion;
struct student_t {
std::string matr_nr;
unsigned points;
int mark;
};
struct date_t {
unsigned dd, mm, yyyy;
friend std::ostream& operator<<(std::ostream& os, date_t const& d) {
std::ostream local(os.rdbuf());
local << std::setw(2) << std::setfill('0') << d.dd <<
"-" << std::setw(2) << std::setfill('0') << d.mm <<
"-" << std::setw(4) << std::setfill('0') << d.yyyy;
return os;
}
};
BOOST_FUSION_ADAPT_STRUCT(student_t,
(std::string,matr_nr)(unsigned,points)(int,mark))
BOOST_FUSION_ADAPT_STRUCT(date_t,
(unsigned,dd)(unsigned,mm)(unsigned,yyyy))
struct klausur {
std::string str_subject;
std::string str_dozent;
date_t date;
unsigned count;
std::vector<student_t> students;
friend std::ostream& operator<<(std::ostream& os, klausur const& k)
{
os << "Fach: " << k.str_subject << '\n';
os << "Dozent: " << k.str_dozent << '\n';
os << "Datum: " << k.date << '\n';
os << "Anzahl: " << k.count << '\n';
for (auto& s : k.students) {
os << "Mat_Nr: " << s.matr_nr << '\n';
os << "Punkte: " << s.points << '\n';
os << "Note: " << s.mark << '\n';
}
return os;
}
};
BOOST_FUSION_ADAPT_STRUCT(klausur,
(std::string , str_subject)
(std::string , str_dozent)
(date_t , date)
(unsigned , count)
(std::vector<student_t> , students)
)
template <typename Iterator, typename Skipper = qi::ascii::blank_type>
struct grammar : qi::grammar<Iterator, klausur(), Skipper> {
grammar() : grammar::base_type(start) {
using namespace qi;
subject = "Fach:" >> lexeme [ +~char_('\n') ] >> eol;
dozent = "Dozent:" >> lexeme [ +~char_('\n') ] >> eol;
date = "Datum:" >> lexeme [uint_ >> '-' >> uint_ >> '-' >> uint_] >> eol;
count = "Anzahl:" >> uint_ >> eol;
points = uint_;
mark = int_parser<int, 10, 1, 1>(); // single base-10 digit
// no clue about this format; what is it? Just a real number?
matnumber = lexeme[digit >> digit >> digit >> punct >> digit >> digit >> digit];
student = matnumber >> points >> mark;
_a_type expected;
klausur_ %= subject
>> dozent
>> date
>> count [ expected = _1 ]
>> repeat(expected) [ student >> (eol|eoi) ]
;
start = klausur_;
BOOST_SPIRIT_DEBUG_NODES((start)(klausur_)(student)(matnumber)(mark)(points)(count)(date)(dozent)(subject))
}
private:
qi::rule<Iterator, klausur(), Skipper> start;
qi::rule<Iterator, klausur(), Skipper, qi::locals<unsigned> > klausur_;
qi::rule<Iterator, std::string() , Skipper> subject;
qi::rule<Iterator, std::string() , Skipper> dozent;
qi::rule<Iterator, date_t(), Skipper> date;
qi::rule<Iterator, unsigned() , Skipper> count;
qi::rule<Iterator, std::string() , Skipper> matnumber;
qi::rule<Iterator, unsigned() , Skipper> points;
qi::rule<Iterator, int() , Skipper> mark;
qi::rule<Iterator, student_t() , Skipper> student;
};
int main() {
using It = std::string::const_iterator;
std::string const input =
R"(Fach: Physics
Dozent: Wayne
Datum: 20-10-2014
Anzahl: 2
729.888 33 5
185.363 35 5)";
It f = input.begin(), l = input.end();
grammar<It> g;
klausur k;
bool ok = qi::phrase_parse(f, l, g, qi::ascii::blank, k);
if (ok) {
std::cout << "Parse success\n";
std::cout << k;
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining input: '" << std::string(f,l) << "'\n";
}
}
输出:
Parse success
Fach: Physics
Dozent: Wayne
Datum: 20-10-2014
Anzahl: 2
Mat_Nr: 729.888
Punkte: 33
Note: 5
Mat_Nr: 185.363
Punkte: 35
Note: 5
以及72行调试输出:
<start>
<try>Fach: Physics\nDozent</try>
<klausur_>
<try>Fach: Physics\nDozent</try>
<subject>
<try>Fach: Physics\nDozent</try>
<success>Dozent: Wayne\nDatum:</success>
<attributes>[[P, h, y, s, i, c, s]]</attributes>
</subject>
<dozent>
<try>Dozent: Wayne\nDatum:</try>
<success>Datum: 20-10-2014\nAn</success>
<attributes>[[W, a, y, n, e]]</attributes>
</dozent>
<date>
<try>Datum: 20-10-2014\nAn</try>
<success>Anzahl: 2\n729.888 33</success>
<attributes>[[20, 10, 2014]]</attributes>
</date>
<count>
<try>Anzahl: 2\n729.888 33</try>
<success>729.888 33 5\n185.36</success>
<attributes>[2]</attributes>
</count>
<student>
<try>729.888 33 5\n185.36</try>
<matnumber>
<try>729.888 33 5\n185.36</try>
<success> 33 5\n185.363 35 5</success>
<attributes>[[7, 2, 9, ., 8, 8, 8]]</attributes>
</matnumber>
<points>
<try> 33 5\n185.363 35 5</try>
<success> 5\n185.363 35 5</success>
<attributes>[33]</attributes>
</points>
<mark>
<try> 5\n185.363 35 5</try>
<success>\n185.363 35 5</success>
<attributes>[5]</attributes>
</mark>
<success>\n185.363 35 5</success>
<attributes>[[[7, 2, 9, ., 8, 8, 8], 33, 5]]</attributes>
</student>
<student>
<try>185.363 35 5</try>
<matnumber>
<try>185.363 35 5</try>
<success> 35 5</success>
<attributes>[[1, 8, 5, ., 3, 6, 3]]</attributes>
</matnumber>
<points>
<try> 35 5</try>
<success> 5</success>
<attributes>[35]</attributes>
</points>
<mark>
<try> 5</try>
<success></success>
<attributes>[5]</attributes>
</mark>
<success></success>
<attributes>[[[1, 8, 5, ., 3, 6, 3], 35, 5]]</attributes>
</student>
<success></success>
<attributes>[[[P, h, y, s, i, c, s], [W, a, y, n, e], [20, 10, 2014], 2, [[[7, 2, 9, ., 8, 8, 8], 33, 5], [[1, 8, 5, ., 3, 6, 3], 35, 5]]]]</attributes><locals>(2)</locals>
</klausur_>
<success></success>
<attributes>[[[P, h, y, s, i, c, s], [W, a, y, n, e], [20, 10, 2014], 2, [[[7, 2, 9, ., 8, 8, 8], 33, 5], [[1, 8, 5, ., 3, 6, 3], 35, 5]]]]</attributes>
</start>
我是一名学生,需要使用 Boost-Library 用 C++ 编写解析器。
因此我在 QI 中写了一个语法,因为我需要解析成一个结构。到目前为止,一切都很好。
我会给你一些示例代码。我认为这比写下整个程序要容易。
说明: 所以首先我们获取一个 txt 文件并读取它,然后解析器遍历它,说 "Parsing is ok!" 并解析到结构中。我们的输出是控制台中的结构。
效果很好,现在来一些代码示例。在这里可以看到Boost Spirit QI中的语法:
subject %= lexeme[lit("Fach: ") >> +(char_("a-zA-Z")) >> lit("\n")]; //works!
dozent %= lexeme[lit("Dozent: ") >> +(char_("a-zA-Z")) >> lit("\n")];
date %= lexeme[lit("Datum: ") >> digit >> digit >> lit("-") >> digit >> digit >> lit("-") >> digit >> digit >> digit >> digit >> lit("\n")];
count %= lexeme[lit("Anzahl: ") >> +digit >> lit("\n")];
points %= lexeme[+digit >> lit("\t")];
mark %= lexeme[digit >> lit("\n")];
matnumber %= lexeme[(digit >> digit >> digit >> punct >> digit >> digit >> digit) >> lit("\t")];
student %= matnumber >> points >> mark;
start %= subject >> dozent >> date >> count >> student;
这很好用,student 的规则带来了一个问题,即我们有一个包含三个部分的元素。 Matnumber、Points 和 mark。你可以想象我的意思,这里是我们尝试解析的 TXT 文件:
Subject: Physics
Dozent: Wayne
Datum: 20-10-2014
Anzahl: 20
729.888 33 5
185.363 35 5
最后两行是rule student。而在 txt 文件中,我们不止这两行。
我们可以把这些行当作 "student" 我们用 typedef 在我们的结构中写了一个向量:
typedef boost::fusion::vector<string, string, string> student_t;
然后我们将在我们的结构中使用它:
struct klausur
{
string str_subject;
string str_dozent;
string str_date;
string count;
string matr_nr;
string points;
string mark;
string ende;
student_t student;
void ToString()
{
cout << "Struct.Fach: " << str_subject << endl;
cout << "Struct.Dozent: " << str_dozent << endl;
cout << "Struct.Datum: " << str_date << endl;
cout << "Struct.Anzahl: " << count << endl;
cout << "Struct.Mat_Nr: " << matr_nr << endl;
cout << "Struct.Punkte: " << points << endl;
cout << "Struct.Note: " << mark << endl;
cout << "Struct.Student<0>: " << vec::at_c<0>(student);
cout << "Struct.Student<1>: " << vec::at_c<1>(student);
cout << "Struct.Student<2>: " << vec::at_c<2>(student);
}
};
然后我们有这样的 BOOST_ADAPT_STRUCT:
BOOST_FUSION_ADAPT_STRUCT(
client::klausur,
(string, str_subject)
(string, str_dozent)
(string, str_date)
(string, count)
(string, matr_nr)
(string, points)
(string, mark)
(student_t, student)
)
你看我们下面有typedef。
然后我们在语法中有我们的规则。
qi::rule<Iterator, string(), ascii::space_type> subject;
qi::rule<Iterator, string(), ascii::space_type> dozent;
qi::rule<Iterator, string(), ascii::space_type> date;
qi::rule<Iterator, string(), ascii::space_type> count;
qi::rule<Iterator, string(), ascii::space_type> matnumber;
qi::rule<Iterator, string(), ascii::space_type> points;
qi::rule<Iterator, string(), ascii::space_type> mark;
qi::rule<Iterator, boost::fusion::vector<boost::fusion::vector<std::string, std::string, std::string> >()> student;
还有我们项目的最终问题……
我们不知道 qi:rule 需要哪种数据类型 BOOST_ADAPT... 可以正常工作。所有其他点都是字符串,但不知道如何实现我们创建的自己的向量。
所有其他规则都工作正常,稍后在结构中,只是向量出了问题。
有人对此有想法吗?如果您需要,我可以上传更多文件和代码片段,但我仍然认为这可能只是我看不到的一个小问题。我四处寻找许多提升主题,但没有找到合适的东西。
我必须补充一点,我只是一个初学者,所以也许我没有正确解释所有内容......是的。希望你能理解。我的英语也不是最好的...
提前感谢您的帮助。
威廉
Spirit 是一个解析器生成器。你似乎并没有真正解析任何东西(你只是 "extract" 字符序列,这更像是标记化)。
我会这样做:
- 使用正确的数据类型
- 使用
blank
跳过(不包括eol
) - 将
eol
期望放在正确的位置 - 把词位放在正确的位置
- 使
date_t
成为自己的类型 - 使
student_t
成为自己的类型 - FIX 使用
std::vector<student_t>()
而不是 ~fusion::vector<student_t>()
的规则(这是一个错误) - 使用
operator<<
打印 - 使用
repeat(n) [ student >> eol ]
解析期望的学生行数 - 使用
qi::locals
实际将预期的学生人数传递给repeat()
#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <iostream>
#include <iomanip>
namespace qi = boost::spirit::qi;
namespace vec = boost::fusion;
struct student_t {
std::string matr_nr;
unsigned points;
int mark;
};
struct date_t {
unsigned dd, mm, yyyy;
friend std::ostream& operator<<(std::ostream& os, date_t const& d) {
std::ostream local(os.rdbuf());
local << std::setw(2) << std::setfill('0') << d.dd <<
"-" << std::setw(2) << std::setfill('0') << d.mm <<
"-" << std::setw(4) << std::setfill('0') << d.yyyy;
return os;
}
};
BOOST_FUSION_ADAPT_STRUCT(student_t,
(std::string,matr_nr)(unsigned,points)(int,mark))
BOOST_FUSION_ADAPT_STRUCT(date_t,
(unsigned,dd)(unsigned,mm)(unsigned,yyyy))
struct klausur {
std::string str_subject;
std::string str_dozent;
date_t date;
unsigned count;
std::vector<student_t> students;
friend std::ostream& operator<<(std::ostream& os, klausur const& k)
{
os << "Fach: " << k.str_subject << '\n';
os << "Dozent: " << k.str_dozent << '\n';
os << "Datum: " << k.date << '\n';
os << "Anzahl: " << k.count << '\n';
for (auto& s : k.students) {
os << "Mat_Nr: " << s.matr_nr << '\n';
os << "Punkte: " << s.points << '\n';
os << "Note: " << s.mark << '\n';
}
return os;
}
};
BOOST_FUSION_ADAPT_STRUCT(klausur,
(std::string , str_subject)
(std::string , str_dozent)
(date_t , date)
(unsigned , count)
(std::vector<student_t> , students)
)
template <typename Iterator, typename Skipper = qi::ascii::blank_type>
struct grammar : qi::grammar<Iterator, klausur(), Skipper> {
grammar() : grammar::base_type(start) {
using namespace qi;
subject = "Fach:" >> lexeme [ +~char_('\n') ] >> eol;
dozent = "Dozent:" >> lexeme [ +~char_('\n') ] >> eol;
date = "Datum:" >> lexeme [uint_ >> '-' >> uint_ >> '-' >> uint_] >> eol;
count = "Anzahl:" >> uint_ >> eol;
points = uint_;
mark = int_parser<int, 10, 1, 1>(); // single base-10 digit
// no clue about this format; what is it? Just a real number?
matnumber = lexeme[digit >> digit >> digit >> punct >> digit >> digit >> digit];
student = matnumber >> points >> mark;
_a_type expected;
klausur_ %= subject
>> dozent
>> date
>> count [ expected = _1 ]
>> repeat(expected) [ student >> (eol|eoi) ]
;
start = klausur_;
BOOST_SPIRIT_DEBUG_NODES((start)(klausur_)(student)(matnumber)(mark)(points)(count)(date)(dozent)(subject))
}
private:
qi::rule<Iterator, klausur(), Skipper> start;
qi::rule<Iterator, klausur(), Skipper, qi::locals<unsigned> > klausur_;
qi::rule<Iterator, std::string() , Skipper> subject;
qi::rule<Iterator, std::string() , Skipper> dozent;
qi::rule<Iterator, date_t(), Skipper> date;
qi::rule<Iterator, unsigned() , Skipper> count;
qi::rule<Iterator, std::string() , Skipper> matnumber;
qi::rule<Iterator, unsigned() , Skipper> points;
qi::rule<Iterator, int() , Skipper> mark;
qi::rule<Iterator, student_t() , Skipper> student;
};
int main() {
using It = std::string::const_iterator;
std::string const input =
R"(Fach: Physics
Dozent: Wayne
Datum: 20-10-2014
Anzahl: 2
729.888 33 5
185.363 35 5)";
It f = input.begin(), l = input.end();
grammar<It> g;
klausur k;
bool ok = qi::phrase_parse(f, l, g, qi::ascii::blank, k);
if (ok) {
std::cout << "Parse success\n";
std::cout << k;
} else {
std::cout << "Parse failed\n";
}
if (f!=l) {
std::cout << "Remaining input: '" << std::string(f,l) << "'\n";
}
}
输出:
Parse success
Fach: Physics
Dozent: Wayne
Datum: 20-10-2014
Anzahl: 2
Mat_Nr: 729.888
Punkte: 33
Note: 5
Mat_Nr: 185.363
Punkte: 35
Note: 5
以及72行调试输出:
<start>
<try>Fach: Physics\nDozent</try>
<klausur_>
<try>Fach: Physics\nDozent</try>
<subject>
<try>Fach: Physics\nDozent</try>
<success>Dozent: Wayne\nDatum:</success>
<attributes>[[P, h, y, s, i, c, s]]</attributes>
</subject>
<dozent>
<try>Dozent: Wayne\nDatum:</try>
<success>Datum: 20-10-2014\nAn</success>
<attributes>[[W, a, y, n, e]]</attributes>
</dozent>
<date>
<try>Datum: 20-10-2014\nAn</try>
<success>Anzahl: 2\n729.888 33</success>
<attributes>[[20, 10, 2014]]</attributes>
</date>
<count>
<try>Anzahl: 2\n729.888 33</try>
<success>729.888 33 5\n185.36</success>
<attributes>[2]</attributes>
</count>
<student>
<try>729.888 33 5\n185.36</try>
<matnumber>
<try>729.888 33 5\n185.36</try>
<success> 33 5\n185.363 35 5</success>
<attributes>[[7, 2, 9, ., 8, 8, 8]]</attributes>
</matnumber>
<points>
<try> 33 5\n185.363 35 5</try>
<success> 5\n185.363 35 5</success>
<attributes>[33]</attributes>
</points>
<mark>
<try> 5\n185.363 35 5</try>
<success>\n185.363 35 5</success>
<attributes>[5]</attributes>
</mark>
<success>\n185.363 35 5</success>
<attributes>[[[7, 2, 9, ., 8, 8, 8], 33, 5]]</attributes>
</student>
<student>
<try>185.363 35 5</try>
<matnumber>
<try>185.363 35 5</try>
<success> 35 5</success>
<attributes>[[1, 8, 5, ., 3, 6, 3]]</attributes>
</matnumber>
<points>
<try> 35 5</try>
<success> 5</success>
<attributes>[35]</attributes>
</points>
<mark>
<try> 5</try>
<success></success>
<attributes>[5]</attributes>
</mark>
<success></success>
<attributes>[[[1, 8, 5, ., 3, 6, 3], 35, 5]]</attributes>
</student>
<success></success>
<attributes>[[[P, h, y, s, i, c, s], [W, a, y, n, e], [20, 10, 2014], 2, [[[7, 2, 9, ., 8, 8, 8], 33, 5], [[1, 8, 5, ., 3, 6, 3], 35, 5]]]]</attributes><locals>(2)</locals>
</klausur_>
<success></success>
<attributes>[[[P, h, y, s, i, c, s], [W, a, y, n, e], [20, 10, 2014], 2, [[[7, 2, 9, ., 8, 8, 8], 33, 5], [[1, 8, 5, ., 3, 6, 3], 35, 5]]]]</attributes>
</start>