提升精神 - 修剪最后一个字符和分隔符

时间:2016-02-12 14:18:40

标签: c++ parsing boost boost-spirit boost-spirit-qi

在这里提升精神新人。

我有一个字符串形式为“Key:Value \ r \ nKey2:Value2 \ r \ n”,我正在尝试解析它。在这种特定的形式中,用Boost Spirit解析它是微不足道的。但是,为了更加健壮,我还需要处理这样的案例:

“我的密钥:值\ r \ n My2ndKey:长< 4个空格>值\ r \ n”

在这种情况下,我需要修剪键/值分隔符之前和之后的前导和尾随空格,以便得到以下映射:

“我的钥匙”,“价值”

“My2ndKey”,“长< 4个空格>值”

我使用qi :: hold来实现这一点但由于不支持的boost :: multi_pass迭代器和我试图使用的嵌入式解析器,我得到了编译错误。必须有一种简单的方法来实现这一目标。

我阅读了以下文章(以及关于这个主题的许多其他文章):

http://boost-spirit.com/home/articles/qi-example/parsing-a-list-of-key-value-pairs-using-spirit-qi/ http://boost-spirit.com/home/2010/02/24/parsing-skippers-and-skipping-parsers/

Boost spirit parsing string with leading and trailing whitespace

我正在寻找我的问题的解决方案,这些文章似乎没有完全涵盖。我还想更好地了解这是如何实现的。作为一个小小的奖金问题,我一直看到'%='运算符,这对我的情况有用吗? MyRule%= MyRule ...用于递归解析?

下面的代码正确地解析了我的字符串,只是它没有删除最后一个非空格字符和分隔符之间的空格。 :(使用的船长是qi :: blank_type(没有EOL的空间)。

谢谢!

template <typename Iterator, typename Skipper>
struct KeyValueParser : qi::grammar<Iterator, std::map<std::string, std::string>(), Skipper> {
  KeyValueParser() : KeyValueParser::base_type(ItemRule) {
    ItemRule = PairRule >> *(qi::lit(END_OF_CMD) >> PairRule);
    PairRule = KeyRule >> PAIR_SEP >> ValueRule;
    KeyRule = +(qi::char_ - qi::lit(PAIR_SEP));
    ValueRule = +(qi::char_ - qi::lit(END_OF_CMD));
  }
  qi::rule<Iterator, std::map<std::string, std::string>(), Skipper> ItemRule;
  qi::rule<Iterator, std::pair<std::string, std::string>(), Skipper> PairRule;
  qi::rule<Iterator, std::string()> KeyRule;
  qi::rule<Iterator, std::string()> ValueRule;
};

1 个答案:

答案 0 :(得分:0)

您需要使用KeyRule = qi::raw[ +(qi::char_ - qi::lit(PAIR_SEP)) ];

为了了解原因,让我们尝试研究解析字符串"a b :"的几种方法。

首先让我们记住以下解析器/指令的工作原理:

  • lexeme[subject]:此指令与subject匹配,同时禁用了跳过者。

  • raw[subject]:丢弃subject的属性并返回指向输入流中匹配字符的迭代器对。

  • +subject:加号解析器尝试匹配其subject的1次或更多次。

  • a-b:差异解析器首先尝试解析b,如果b成功,则a-b失败。 b失败时,它与a匹配。

  • char_:匹配任何字符。这是一个PrimitiveParser

  • lit(':'):匹配':'但忽略其属性。这是一个PrimitiveParser

  1. lexeme[ +(char_ - lit(':')) ] :通过从规则中删除队友,您有一个隐含的词汇。由于没有船长,它是这样的:
  2.   

    'a' - &gt; ':'失败,char_匹配'a',当前合成的属性为“a”   '' - &gt; ':'失败,char_匹配'',当前合成的属性为“a”   'b' - &gt; ':'失败,char_匹配'b',当前合成的属性为“a b”   '' - &gt; ':'失败,char_匹配'',当前合成的属性为“a b”   ':' - &gt; ':'成功,最终合成属性为“a b”

    1. +(char_ - lit(':')) :由于它有一个队长,因此每个PrimitiveParser在尝试之前都会预先跳过:
    2.   

      'a' - &gt; ':'失败,char_匹配'a',当前合成的属性为“a”   '' - &gt;在尝试':'之前跳过此选项   'b' - &gt; ':'失败,char_匹配'b',当前合成的属性为“ab”
        '' - &gt;在尝试':'之前跳过此选项   ':' - &gt; ':'成功,最终合成属性为“ab”

      1. raw[ +(char_ - lit(':') ) ] :主题与2.完全相同。 raw指令忽略"ab"并返回从'a''b'的迭代器对。由于规则的属性为std::string,因此会从该迭代器对构造一个字符串,从而生成"a b"这就是您想要的。