boost::spirit::karma вывод строки в кавычках
Я пытаюсь избежать строки в кавычках, используя boost:: spirit:: karma. Это прекрасно работает, если это просто строка. Однако для строки в boost:: варианте в std::vector это не так. Однако просто печать строки работает, я не совсем понимаю, почему.
Строка (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;
}
3 ответа
Если вы повторяете свои типы данных, вы должны повторять свои правила.
#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;
}
Отредактировано В случае, если рекурсия не была целью, вот отредактированная версия, которая решает проблему и экранирующая цитата: Live on Coliru (или просто источник здесь)
Хм. Похоже, что вы могли быть после рекурсивного атрибута / правила:
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';
}
}
#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;
}