2013-08-07 55 views
2

我想用boost :: spirit :: karma在引號中轉義字符串。這工作正常,如果它只是一個字符串。但是,對於std :: vector中boost :: variant類型的字符串,它不會。只是打印字符串確實有效,但我不明白爲什麼。boost :: spirit :: karma輸出字符串的引號

行(1)工作正常,但沒有做我想做的。第(2)行應該這樣做,但不是。

#include <iostream> 
#include <string> 
#include <boost/variant.hpp> 
#include <boost/spirit/include/karma.hpp> 
namespace karma = boost::spirit::karma; 

typedef std::vector<boost::variant<int, std::string>> ParameterList; 
typedef boost::variant<int, std::string, ParameterList> Parameter; 

main() 
{ 
    using karma::int_; 
    using boost::spirit::ascii::string; 
    using karma::eol; 
    using karma::lit; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 

    // (1) 
    karma::rule<std::back_insert_iterator<std::string>, ParameterList()> parameterListRule = (int_ | string) % lit(", "); // This works! 

    // (2) 
    //karma::rule<std::back_insert_iterator<std::string>, ParameterList()> parameterListRule = (int_ | (lit('"') << string << lit('"'))) % lit(", "); // This does not work 

    karma::rule<std::back_insert_iterator<std::string>, Parameter()> parameterRule = (int_ | (lit('"') << string << lit('"')) | parameterListRule) << eol; // This does work, even though it also escapes the string in a pair of quotation marks 

    karma::generate(sink, parameterRule, 1); // Works 
    karma::generate(sink, parameterRule, "foo"); // Works 
    karma::generate(sink, parameterRule, Parameter(ParameterList{1, "foo"})); // Only works using rule (1), not with (2) 
    std::cout << generated; 
} 

回答

2

如果你迭代你的數據類型,你應該迭代你的規則。

#include <iostream> 
#include <string> 
#include <boost/variant.hpp> 
#include <boost/spirit/include/karma.hpp> 
namespace karma = boost::spirit::karma; 

typedef boost::variant<int, std::string> Item; 
typedef std::vector<Item> ParameterList; 
typedef boost::variant<int, std::string, ParameterList> Parameter; 

int main() 
{ 
    using karma::int_; 
    using boost::spirit::ascii::string; 
    using karma::eol; 
    using karma::lit; 

    std::string generated; 
    std::back_insert_iterator<std::string> sink(generated); 

    karma::rule<std::back_insert_iterator<std::string>, Item()> itemRule = 
     int_ | (lit('"') << string << lit('"')); 

    karma::rule<std::back_insert_iterator<std::string>, ParameterList()> 
    parameterListRule = itemRule % lit(", "); 

    karma::rule<std::back_insert_iterator<std::string>, Parameter()> 
    parameterRule = (int_ | (lit('"') << string << lit('"')) | parameterListRule) << eol; 

    karma::generate(sink, parameterRule, 1); 
    karma::generate(sink, parameterRule, "foo"); 
    karma::generate(sink, parameterRule, Parameter(ParameterList {1, "foo"})); 
    std::cout << generated; 

    return 0; 
} 
+0

這解決了它到底。關於爲什麼第(1)行和第(2)行不行的任何解釋? – Xoph

+0

對不起沒有。從組合本身就可以期待它,但似乎業力在轉發這裏的屬性時有一些問題,雖然'karma :: lit'不公開任何。但我不是這裏的專家,也許@sehe更多地瞭解這一點。但你學會迅速解決這些怪癖;-) –

3

編輯如果遞歸是目標,下面是解決問題和報價逃逸編輯版:Live on Coliru(或just source here

嗯。它看起來像你可能是一個遞歸屬性/規則後:

typedef boost::make_recursive_variant<int, std::string, std::vector<boost::recursive_variant_> >::type Parameter; 

只是在這種情況下,這裏有一個簡單的方法來生成:

gen = int_ | string | gen % ", "; 

現在,您的標題表明,含雙串 - 引用應該逃避這些。我建議

str = '"' << *('\\' << char_('"') | char_) << '"'; 
gen = int_ | str | gen % ", "; 

類似下面的測試案例

for (Parameter p : Parameters { 
     1, 
     "foo", 
     Parameters { 1, "foo" }, 
     Parameters { 1, "escape: \"foo\"", Parameters { "2", "bar" } } 
    }) 
{ 
    std::cout << karma::format(gen, p) << '\n'; 
} 

結果:

1 
"foo" 
1, "foo" 
1, "escape: \"foo\"", "2", "bar" 

如果遞歸是一個真正的功能,你會希望看到嵌套的參數列表的分組:

gen = int_ | str | '{' << gen % ", " << '}'; 

現在打印

1 
"foo" 
{1, "foo"} 
{1, "escape: \"foo\"", {"2", "bar"}} 

完整的示例程序:

#include <boost/variant.hpp> 
#include <boost/spirit/include/karma.hpp> 

namespace karma = boost::spirit::karma; 
typedef boost::make_recursive_variant<int, std::string, std::vector<boost::recursive_variant_> >::type Parameter; 
typedef std::vector<Parameter> Parameters; 

int main() 
{ 
    typedef boost::spirit::ostream_iterator It; 

    karma::rule<It, Parameter()> gen; 
    karma::rule<It, std::string()> str; 

    str = '"' << *('\\' << karma::char_('"') | karma::char_) << '"'; 
    gen = (karma::int_ | str | '{' << gen % ", " << '}'); 

    for (Parameter p : Parameters { 
      1, 
      "foo", 
      Parameters { 1, "foo" }, 
      Parameters { 1, "escape: \"foo\"", Parameters { "2", "bar" } } 
     }) 
    { 
     std::cout << karma::format(gen, p) << '\n'; 
    } 
} 
+0

我很高興你找到它。 :) –

+0

(增加了一個解決方案,簡化了規則,並修復了引用,但並沒有改變屬性結構,爲了完整性) – sehe

+0

謝謝,我沒有試圖讓它遞歸定義,應該明確說明。你的解決方案非常好,解決了它。我標記了Mike_M,因爲它確切地指出了問題並且不引入遞歸。不過,我仍然不明白爲什麼添加引號使代碼無法正常工作。 – Xoph

0
#include <iostream> 
#include <boost/spirit/include/karma.hpp> 
#include <boost/spirit/include/karma_right_alignment.hpp> 

using namespace boost; 

void foo(char* buffer, uint32_t lhOid) { 
    boost::spirit::karma::generate(buffer, boost::spirit::right_align(20)[boost::spirit::karma::int_], lhOid); 
    *buffer = '\0'; 
} 

int main() { 
    char arr[21]; 
    foo(arr, 1234); 
    std::cout.write(arr, 21) << std::endl; 
    return 0; 
} 
相關問題