我有一个包含表单数据的文件:
fractal mand1 {
;lkkj;kj;
}
fractal mand2 {
if (...) {
blablah;
}
}
fractal julia1 {
a = ss;
}
我想提取数据容器的名称,因此我想检索包含特定案例mand1
,mand2
,julia1
的数据。
我已阅读有关parsing a number list into a vector的示例,但我想将语法保存在单独的文件中。
我创建了一个表示语法的结构,然后我使用它来解析包含数据的字符串。我希望输出像
mand1
mand2
julia1
相反,我获得了
mand1 {
;lkkj;kj;
}
fractal mand2 {
if (...) {
blablah;
}
}
fractal julia1 {
a = ss;
}
我的解析器识别第一个fractal
术语,但然后它将文件的其余部分解析为单个字符串项,而不是根据需要解析它。
我做错了什么?
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <vector>
#include <iostream>
using boost::spirit::ascii::space;
using boost::spirit::ascii::space_type;
using boost::spirit::qi::phrase_parse;
using boost::spirit::qi::lit;
using boost::spirit::qi::lexeme;
using boost::spirit::qi::skip;
using boost::spirit::ascii::char_;
using boost::spirit::ascii::no_case;
using boost::spirit::qi::rule;
typedef std::string::const_iterator sit;
template <typename Iterator>
struct FractalListParser : boost::spirit::qi::grammar<Iterator, std::vector<std::string>(), boost::spirit::ascii::space_type> {
FractalListParser() : FractalListParser::base_type(start) {
no_quoted_string %= *(lexeme[+(char_ - '"')]);
start %= *(no_case[lit("fractal")] >> no_quoted_string >> '{' >> *(skip[*(char_)]) >> '}');
}
rule<Iterator, std::string(), space_type> no_quoted_string;
rule<Iterator, std::vector<std::string>(), space_type> start;
};
int main() {
const std::string fractalListFile(R"(
fractal mand1 {
;lkkj;kj;
}
fractal mand2 {
if (...) {
blablah;
}
}
fractal julia1 {
a = ss;
}
)");
std::cout << "Read Test:" << std::endl;
FractalListParser<sit> parser;
std::vector<std::string> data;
bool r = phrase_parse(fractalListFile.begin(), fractalListFile.end(), parser, space, data);
for (auto& i : data) std::cout << i << std::endl;
return 0;
}
答案 0 :(得分:3)
如果您使用错误处理,您将发现解析失败,并且没有任何有效解析:
<强> Live On Coliru 强>
输出:
Read Test:
Parse success:
----
mand1 {
;lkkj;kj;
}
fractal mand2 {
if (...) {
blablah;
}
}
fractal julia1 {
a = ss;
}
Remaining unparsed input: 'fractal mand1 {
;lkkj;kj;
}
fractal mand2 {
if (...) {
blablah;
}
}
fractal julia1 {
a = ss;
}
'
你可能想忽略&#34; body&#34; ({}
之间)。因此,我想您实际上想要omit
属性:
>> '{' >> *(omit[*(char_)]) >> '}'
而不是skip(*char_)
。
表达式*char_
是贪婪的,并且总是匹配到输入的结尾......你可能想限制字符集:
在&#34;名称&#34; *~char_("\"{")
以避免&#34;进食&#34;所有的身体也是如此。为避免匹配空格,请使用graph
(例如+graph - '"'
)。如果你想解析&#34;标识符&#34;明确例如。
alpha > *(alnum | char_('_'))
*~char_('}')
或*(char_ - '}')
中的(后者效率较低)。
可选量词的嵌套效率不高:
*(omit[*(char_)])
最坏情况运行时间会非常慢(因为*char_
可能为空,*(omit[*(char_)])
也可能为空)。说出你的意思:
omit[*char_]
获得词汇的最简单方法是从规则声明中删除船长(另请参阅Boost spirit skipper issues)
程序逻辑:
由于您的示例包含嵌套块(例如mand2
),因此您需要递归处理块,以避免调用外部块的第一个}
:
block = '{' >> -block % (+~char_("{}")) >> '}';
松散的提示:
使用BOOST_SPIRIT_DEBUG
找出拒绝/匹配解析的位置。例如。在重构规则之后:
我们得到了输出(On Coliru):
Read Test:
<start>
<try>fractal mand1 {\n </try>
<no_quoted_string>
<try>mand1 {\n ;lkkj;kj</try>
<success> {\n ;lkkj;kj;\n}\n\n</success>
<attributes>[[m, a, n, d, 1]]</attributes>
</no_quoted_string>
<body>
<try>{\n ;lkkj;kj;\n}\n\nf</try>
<fail/>
</body>
<success>fractal mand1 {\n </success>
<attributes>[[]]</attributes>
</start>
Parse success:
Remaining unparsed input: 'fractal mand1 {
;lkkj;kj;
}
fractal mand2 {
if (...) {
blablah;
}
}
fractal julia1 {
a = ss;
}
'
这个输出帮助我发现我实际上忘记了身体规则中的- '}'
部分......:)
当该规则定义中没有涉及语义操作时,%=
不需要fractal
您可能希望确保fractalset multi { .... }
实际上是一个单独的词,因此您不匹配//#define BOOST_SPIRIT_DEBUG
#include <boost/spirit/include/qi.hpp>
#include <iostream>
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct FractalListParser : qi::grammar<Iterator, std::vector<std::string>(), qi::space_type> {
FractalListParser() : FractalListParser::base_type(start) {
using namespace qi;
identifier = alpha > *(alnum | char_('_'));
block = '{' >> -block % +~char_("{}") >> '}';
start = *(
no_case["fractal"] >> identifier >> block
);
BOOST_SPIRIT_DEBUG_NODES((start)(block)(identifier))
}
qi::rule<Iterator, std::vector<std::string>(), qi::space_type> start;
// lexemes (just drop the skipper)
qi::rule<Iterator, std::string()> identifier;
qi::rule<Iterator> block; // leaving out the attribute means implicit `omit[]`
};
int main() {
using It = boost::spirit::istream_iterator;
It f(std::cin >> std::noskipws), l;
std::cout << "Read Test:" << std::endl;
FractalListParser<It> parser;
std::vector<std::string> data;
bool r = qi::phrase_parse(f, l, parser, qi::space, data);
if (r) {
std::cout << "Parse success:\n";
for (auto& i : data)
std::cout << "----\n" << i << "\n";
} else {
std::cout << "Parse failed\n";
}
if (f != l)
std::cout << "Remaining unparsed input: '" << std::string(f,l) << "'\n";
}
有了这些,我们可以有一个工作演示:
<强> docs 强>
Read Test:
Parse success:
----
mand1
----
mand2
----
julia1
打印:
success: function (data) {
var res = $('#meetTable tr th#eventNames');
for (var i=0;i < res.length; i++){
if (data.indexOf(res[i].innerText) >=0)
{
res[i].style.color = 'green'
}
}