C++ 提升精神-修剪最后一个字符和分隔符之间的空格

C++ 提升精神-修剪最后一个字符和分隔符之间的空格,c++,parsing,boost,boost-spirit,boost-spirit-qi,C++,Parsing,Boost,Boost Spirit,Boost Spirit Qi,我是新来的 我有一个格式为“Key:Value\r\nKey2:Value2\r\n”的字符串,正试图对其进行分析。在这种特定的形式下,用Boost-Spirit进行解析非常简单。但是,为了更加稳健,我还需要处理以下情况: “我的密钥:Value\r\n My2ndKey:LongValue\r\n” 在这种情况下,我需要在键/值分隔符之前和之后修剪前导空格和尾随空格,以便得到以下映射: “我的钥匙”、“价值” “My2ndKey”、“LongValue” 为了实现这一点,我使用了qi::hol

我是新来的

我有一个格式为“Key:Value\r\nKey2:Value2\r\n”的字符串,正试图对其进行分析。在这种特定的形式下,用Boost-Spirit进行解析非常简单。但是,为了更加稳健,我还需要处理以下情况:

“我的密钥:Value\r\n My2ndKey:LongValue\r\n”

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

“我的钥匙”、“价值”

“My2ndKey”、“LongValue”

为了实现这一点,我使用了qi::hold,但由于不支持boost::multi_-pass迭代器和我尝试使用的嵌入式解析器,因此我出现了编译错误。必须有一个简单的方法来实现这一点

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

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

下面的代码正确地解析了我的字符串,只是没有删除最后一个非空格字符和分隔符之间的空格:(使用的跳过程序是qi::blank_类型(没有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;
};
模板
结构KeyValueParser:qi::grammar{
KeyValueParser():KeyValueParser::基本类型(ItemRule){
ItemRule=PairRule>>*(qi::lit(命令的结尾)>>PairRule);
PairRule=KeyRule>>PAIR\u SEP>>ValueRule;
KeyRule=+(qi::char\uqi::lit(PAIR\u SEP));
ValueRule=+(qi::char_uqi::lit(命令的结尾));
}
qi::规则项规则;
齐:治廉;
qi::规则键规则;
qi::规则值规则;
};

您需要使用
KeyRule=qi::raw[+(qi::char\uqi::lit(PAIR\u SEP))];


为了了解原因,让我们尝试研究几种解析字符串
“ab:”
的方法

首先,让我们记住以下解析器/指令是如何工作的:

  • :禁用跳过程序时,此指令与主题匹配

  • :放弃主题的属性,并返回指向输入流中匹配字符的迭代器对

  • :plus解析器尝试匹配其
    主题的1倍或更多倍

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

  • 字符
    :匹配任何字符。它是一个

  • lit(“:”)
    :匹配
    “:”
    ,但忽略其属性。它是一个


  • lexeme[+(char_u-lit(':'))]
    :从规则中删除skipper,您就有了一个隐式lexeme。由于没有skipper,它是这样的:
  • “a'->
    ':'
    失败,
    char\u
    与“a”匹配,当前合成的属性为“a”
    “->
    ”:“
    失败,
    字符匹配“”,当前合成属性为“a”
    “b”->
    :”
    失败,
    字符与“b”匹配,当前合成属性为“ab”
    “->
    ”:“
    失败,
    字符匹配“”,当前合成属性为“ab”
    “:”->
    ”:“
    成功,最终合成的属性为“a b”


  • +(char.-lit(“:”)
    :由于它有一个skipper,每个原语分析器在尝试之前都会预先跳过:
  • “a'->
    ':'
    失败,
    char\u
    与“a”匹配,当前合成的属性为“a”
    ''->在尝试
    之前跳过此操作:'

    “b”->
    :”
    失败,
    字符与“b”匹配,当前合成属性为“ab”
    ''->在尝试
    之前跳过此操作:'

    “:”->
    ”:“
    成功,最终合成的属性为“ab”


  • raw[+(char:)]
    :主题与
    2.
    完全相同。raw指令忽略
    “ab”
    并返回从
    'a'
    'b'
    的迭代器对。由于规则的属性是
    std::string
    ,因此将从该迭代器对构造字符串,从而生成所需的
    “a b”

  • 您需要使用
    KeyRule=qi::raw[+(qi::char\uqi::lit(PAIR\u SEP))];


    为了了解原因,让我们尝试研究几种解析字符串
    “ab:”
    的方法

    首先,让我们记住以下解析器/指令是如何工作的:

    • :禁用跳过程序时,此指令与主题匹配

    • :放弃主题的属性,并返回指向输入流中匹配字符的迭代器对

    • :plus解析器尝试匹配其
      主题的1倍或更多倍

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

    • 字符
      :匹配任何字符。它是一个

    • lit(“:”)
      :匹配
      “:”
      ,但忽略其属性。它是一个


  • lexeme[+(char_u-lit(':'))]
    :从规则中删除skipper,您就有了一个隐式lexeme。由于没有skipper,它是这样的:
  • “a'->
    ':'
    失败,
    char\u
    与“a”匹配,当前合成的属性为“a”
    “->
    ”:“
    失败,
    字符匹配“”,当前合成属性为“a”
    “b”->
    :”
    失败,
    字符与当前合成器的“b”匹配