2016-02-12 67 views
1

在這裏提升靈魂新手。提升精神 - 修剪最後一個字符和分隔符之間的空格

我有一個字符串形式的「Key:Value \ r \ nKey2:Value2 \ r \ n」,我試圖解析。在這個特定的形式中,用Boost Spirit進行解析是微不足道的。但是,爲了更加穩健,我還需要處理這樣的情況下一個:

「我的鑰匙:價值\ r \ n My2ndKey:龍< 4個空格>值\ r \ n」 個

在這種情況下,我需要修剪領導和前後鍵/值分隔後的空間,讓我得到如下圖:

「我的鑰匙」,「價值」

「My2ndKey」,「長< 4個空格>值「

我玩過機智h 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 ...用於遞歸解析?

下面的代碼正確地解析了我的字符串,只是它沒有刪除最後一個非空格字符和分隔符之間的空格。 :(使用的隊長是補氣:: 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; 
}; 
+0

如果不是你做了什麼,而是提供了[this](http://coliru.stacked-crooked.com/a/3b30f7a280f0d0e1)之類的東西,那麼幫助你會容易得多。我很確定這是重複的,儘管目前我找不到它,[http://coliru.stacked-crooked.com/a/7539f0ebf856e242]是一個可能的解決方案。關於你關於'%='的問題,你可以看到[這裏](http://www.boost.org/libs/spirit/doc/html/spirit/qi/reference/nonterminal/rule.html#spirit.qi。 reference.nonterminal.rule.expression_semantics),它基本上與'='相同,除非有語義動作。 – llonesmiz

+0

這正是我正在尋找的,謝謝! 您可以將解決方案發布爲答案,這樣我就可以標記它嗎? 我之所以沒有發佈完整的代碼是因爲我正在尋找更多的提示或解釋,而不是像您提供的完整解決方案,但我將在未來更加明確。 :) 即使解決方案正常工作,我也不完全瞭解它。我注意到你爲Key/Value規則引入了隊長,但我會認爲qi :: raw指令也會佔用前導/尾隨空格。你可以解釋嗎?謝謝 另外,感謝您的%=解釋鏈接! – XanderLo

+0

[This](http://stackoverflow.com/questions/19591694/how-to-extract-trimmed-text-using-boost-spirit)是我試圖找到的重複。可悲的是,它並沒有真正解釋它是如何工作的。我會試着給出一個解釋。 – llonesmiz

回答

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(':')) ]:從您的規則去除隊長你有一個隱含的語義。由於沒有船長它是這樣的:

'一' - >':'失敗,char_比賽 'A',當前合成屬性是 「一」
'' - >':'失敗,char_匹配 '',當前合成屬性爲 「a」
'b' - >':'失敗,char_匹配 'b',當前合成屬性是 「AB」
'' - >':'失敗,char_匹配 '',當前合成的屬性是「ab」
':' - >':'成功,最終合成的屬性是 「AB」


  • +(char_ - lit(':')):因爲它有一個船長每PrimitiveParser將預先跳躍前正在嘗試:
  • 'A' - >':'失敗,char_匹配 '一個',當前合成屬性爲 「a」
    '' - >這是':'之前跳過試圖
    'B' - >':'失敗,char_匹配 'B',當前合成屬性是 「AB」
    '' - >這是':'之前跳過試圖
    ':' - >':'成功,最終合成的屬性是 「AB」


  • raw[ +(char_ - lit(':')) ]:主體是完全一樣的2.。 raw指令忽略"ab"並返回從'a''b'的迭代器對。由於您的規則屬性爲std::string,因此從該迭代器對構造出一個字符串,從而得到您想要的"a b"
  • +0

    感謝您的徹底解答。我正確理解其他指令,但我不知道qi :: raw在返回有效保持船長之間的迭代器對之前考慮了船長。 :) – XanderLo

    相關問題