我正在尝试使用Spirit.Qi来解析一个简单的文件格式,该格式具有用等号分隔的键值对。该文件还支持注释和空行以及引用值。
我几乎可以按预期工作,但是,任何空白行或注释都会导致将空键值对添加到地图中。交换地图时,不会生成任何空白条目。
#include <fstream>
#include <iostream>
#include <string>
#include <map>
#include "boost/spirit/include/qi.hpp"
#include "boost/spirit/include/karma.hpp"
#include "boost/fusion/include/std_pair.hpp"
using namespace boost::spirit;
using namespace boost::spirit::qi;
////////////////////////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
std::ifstream ifs("file");
ifs >> std::noskipws;
std::map< std::string, std::string > vars;
auto value = as_string[*print];
auto quoted_value = as_string[lexeme['"' >> *(print-'"') >> '"']];
auto key = as_string[alpha >> *(alnum | char_('_'))];
auto kvp = key >> '=' >> (quoted_value | value);
phrase_parse(
istream_iterator(ifs),
istream_iterator(),
-kvp % eol,
('#' >> *(char_-eol)) | blank,
vars);
std::cout << "vars[" << vars.size() << "]:" << std::endl;
std::cout << karma::format(*(karma::string << " -> " << karma::string << karma::eol), vars);
return 0;
}
one=two
three=four
# Comment
five=six
vars[4]:
->
one -> two
three -> four
five -> six
空键值对来自何处?我怎样才能防止它被生成?
答案 0 :(得分:1)
首先,您的程序有未定义的行为(实际上它在我的系统上崩溃)。原因是您不能使用auto
表达式来存储有状态解析器表达式。
请参阅Assigning parsers to auto variables,boost spirit V2 qi bug associated with optimization level和其他人。参见例如these answers提供了解决此限制的有用策略。
其次,空行是因为语法。
之间存在差异
(-kvp) % qi::eol
或
-(kvp % qi::eol)
第一个将导致&#34;可选地解析kvp&#34;然后按&#34;将结果推送到属性容器&#34;。
后者可选地&#34;将1个或更多kvp解析为容器&#34;。请注意,如果空值不匹配,则不会推送空值。
我建议
key
和value
词句(只需将Skipper放在规则声明上,真的);您可能不希望'key name 1=value 1
解析为"keyname1" -> "value1"
。您可能也不想允许key # no value\n
。using namespace boost::spirit
。这是个坏主意。相信我:/ +eol
代替eol
允许空行,这似乎是您想要的<强> Live On Coliru 强>
#define BOOST_SPIRIT_DEBUG
#include "boost/spirit/include/qi.hpp"
#include "boost/spirit/include/karma.hpp"
#include "boost/fusion/include/std_pair.hpp"
#include <fstream>
#include <map>
namespace qi = boost::spirit::qi;
namespace karma = boost::spirit::karma;
template <typename It, typename Skipper, typename Data>
struct kvp_grammar : qi::grammar<It, Data(), Skipper> {
kvp_grammar() : kvp_grammar::base_type(start) {
using namespace qi;
value = raw [*print];
quoted_value = '"' >> *~char_('"') >> '"';
key = raw [ alpha >> *(alnum | '_') ];
kvp = key >> '=' >> (quoted_value | value);
start = -(kvp % +eol);
BOOST_SPIRIT_DEBUG_NODES((value)(quoted_value)(key)(kvp))
}
private:
using Pair = std::pair<std::string, std::string>;
qi::rule<It, std::string(), Skipper> value;
qi::rule<It, Pair(), Skipper> kvp;
qi::rule<It, Data(), Skipper> start;
// lexeme:
qi::rule<It, std::string()> quoted_value, key;
};
template <typename Map>
bool parse_vars(std::istream& is, Map& data) {
using It = boost::spirit::istream_iterator;
using Skipper = qi::rule<It>;
kvp_grammar<It, Skipper, Map> grammar;
It f(is >> std::noskipws), l;
Skipper skipper = ('#' >> *(qi::char_-qi::eol)) | qi::blank;
return qi::phrase_parse(f, l, grammar, skipper, data);
}
int main() {
std::ifstream ifs("input.txt");
std::map<std::string, std::string> vars;
if (parse_vars(ifs, vars)) {
std::cout << "vars[" << vars.size() << "]:" << std::endl;
std::cout << karma::format(*(karma::string << " -> " << karma::string << karma::eol), vars);
}
}
输出(目前在Coliru上打破):
vars[3]:
five -> six
one -> two
three -> four
使用调试信息:
<kvp>
<try>one=two\nthree=four\n\n</try>
<key>
<try>one=two\nthree=four\n\n</try>
<success>=two\nthree=four\n\n# C</success>
<attributes>[[o, n, e]]</attributes>
</key>
<quoted_value>
<try>two\nthree=four\n\n# Co</try>
<fail/>
</quoted_value>
<value>
<try>two\nthree=four\n\n# Co</try>
<success>\nthree=four\n\n# Comme</success>
<attributes>[[t, w, o]]</attributes>
</value>
<success>\nthree=four\n\n# Comme</success>
<attributes>[[[o, n, e], [t, w, o]]]</attributes>
</kvp>
<kvp>
<try>three=four\n\n# Commen</try>
<key>
<try>three=four\n\n# Commen</try>
<success>=four\n\n# Comment\nfiv</success>
<attributes>[[t, h, r, e, e]]</attributes>
</key>
<quoted_value>
<try>four\n\n# Comment\nfive</try>
<fail/>
</quoted_value>
<value>
<try>four\n\n# Comment\nfive</try>
<success>\n\n# Comment\nfive=six</success>
<attributes>[[f, o, u, r]]</attributes>
</value>
<success>\n\n# Comment\nfive=six</success>
<attributes>[[[t, h, r, e, e], [f, o, u, r]]]</attributes>
</kvp>
<kvp>
<try>five=six\n</try>
<key>
<try>five=six\n</try>
<success>=six\n</success>
<attributes>[[f, i, v, e]]</attributes>
</key>
<quoted_value>
<try>six\n</try>
<fail/>
</quoted_value>
<value>
<try>six\n</try>
<success>\n</success>
<attributes>[[s, i, x]]</attributes>
</value>
<success>\n</success>
<attributes>[[[f, i, v, e], [s, i, x]]]</attributes>
</kvp>
<kvp>
<try></try>
<key>
<try></try>
<fail/>
</key>
<fail/>
</kvp>