【问题标题】:boost::spirit::karma output of string in quotation marksboost::spirit::karma 输出引号中的字符串
【发布时间】:2013-08-07 10:51:58
【问题描述】:

我正在尝试使用 boost::spirit::karma 转义引号中的字符串。如果它只是一个字符串,这很好。但是,对于 std::vector 中的 boost::variant 中的字符串,它不会。只是打印字符串确实有效,但我不太明白为什么。

第 (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;
}

【问题讨论】:

    标签: boost boost-spirit boost-variant boost-spirit-karma


    【解决方案1】:

    已编辑如果递归不是目标,这是一个解决问题和引号转义的已编辑版本:@ 987654321@(或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';
        }
    }
    

    【讨论】:

    • 很高兴你找到了它。 :)
    • (为了完整起见,添加了一个简化规则的解决方案,并修复了引用但不改变属性结构)
    • 谢谢,我并没有试图递归定义它,应该清楚地说明这一点。您的解决方案非常好并且解决了它。我标记了 Mike_M,因为它准确地指出了问题并且没有引入递归。但是我仍然不明白为什么添加引号会使代码不起作用。
    【解决方案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;
    }
    

    【讨论】:

    • 这完全解决了它。关于为什么第 (1) 行有效而第 (2) 行无效的任何解释?
    • 对不起,没有。从作文本身可以预期,但似乎 karma 在此处转发属性存在一些问题,尽管karma::lit 没有公开任何问题。但我不是这里的专家,也许@sehe 对此了解更多。但是你学会快速解决这些怪癖;-)
    【解决方案3】:
    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多