Как разобрать CSV как сбежавший String с Boost Spirit? - PullRequest
2 голосов
/ 24 марта 2020

Для моего express проекта парсера я хотел бы использовать CSV, например, с экранированием: "" для экранирования "

Примеры:

 "\"hello\"",
 "   \"  hello \"  ",
 "  \"  hello \"\"stranger\"\" \"  ",

онлайн-компиляция и попытка: https://wandbox.org/permlink/5uchQM8guIN1k7aR

мое текущее правило синтаксического анализа анализирует только первые 2 теста

qi::rule<std::string::const_iterator, qi::blank_type, utree()> double_quoted_string
    = '"' >> qi::no_skip[+~qi::char_('"')] >> '"';

Я нашел этот вопрос переполнения стека и один ответ дан с использованием духа:

Как я могу читать и анализировать CSV-файлы в C ++?

start       = field % ',';
field       = escaped | non_escaped;
escaped     = lexeme['"' >> *( char_ -(char_('"') | ',') | COMMA | DDQUOTE)  >> '"'];
non_escaped = lexeme[       *( char_ -(char_('"') | ',')                  )        ];
DDQUOTE     = lit("\"\"")       [_val = '"'];
COMMA       = lit(",")          [_val = ','];

(я не знаю, как связать ответы, поэтому, если интересует поиск "Вы должны гордиться, когда Вы используете что-то такое прекрасное, как boost :: spirit ")

к сожалению, это не компилируется для меня - и даже годы анализа сообщений об ошибках C ++ не подготовили меня к наводнениям об ошибке Spirit :) и, если я понимаю, Правильно, правило будет ожидать , в качестве разделителя строк, что может быть неправильно для моего проекта парсера выражений

expression = "strlen( \"hello \"\"you\"\" \" )+1";
expression = "\"hello \"";
expression = "strlen(concat(\"hello\",\"you\")+3";

, или же правило необязательно ждать , и ) в этом случае?

надеюсь, я не задам слишком много глупых вопросов но ответы на эти вопросы очень помогают мне проникнуть в дух, сам синтаксический анализ выражений почти работает, за исключением экранирования строки

thx для любой помощи

ОБНОВЛЕНИЕ: это похоже на работу мне, по крайней мере, он анализирует строки, но удаляет экранированный " из строки, есть ли лучший выход отладки для строк? " " " " "h" "e" "l" "l" "o" " " "s" "t" "r" "a" "n" "g" "e" "r" " " не очень хорошо читается

qi::rule<std::string::const_iterator, utree()> double_quoted_string
  = qi::lexeme['"' >> *(qi::char_ - (qi::char_('"')) | qi::lit("\"\"")) >> '"'];

1 Ответ

1 голос
/ 24 марта 2020

Вы можете упростить вопрос до этого. Как заставить строку в двойных кавычках принимать «двойные двойные кавычки» для экранирования встроенного символа двойной кавычки?

Простой синтаксический анализатор строк без escape-символов:

qi::rule<It, std::string()> s = '"' >> *~qi::char_('"') >> '"';

Теперь также принять одиночный экранированный " по желанию, просто добавьте:

s = '"' >> *("\"\"" >> qi::attr('"') | ~qi::char_('"')) >> '"';

Другие примечания:

  • в вашем онлайн-примере использование no_skip небрежно: это будет анализировать "foo bar" и " foo bar " до foo bar (обрезка пробела). Вместо этого удалите шкипер из правила, чтобы сделать его неявно лексемным ( снова ).
  • Ваш анализатор не сделал принимать пустые строки (это может быть то, что вы хотите, но это не обязательно)
  • использование utree, вероятно, усложнит вашу жизнь больше, чем вы хотите

Упрощенно:

Live On Coliru

#define BOOST_SPIRIT_DEBUG
#include <iostream>
#include <iomanip>
#include <string>
#include <boost/spirit/include/qi.hpp>

namespace qi = boost::spirit::qi;
namespace fu = boost::fusion;

int main()
{
    auto tests = std::vector<std::string>{
         R"( "hello" )",
         R"(    "  hello " )",
         R"(  "  hello ""escaped"" "  )",
    };
    for (const std::string& str : tests) {
        auto iter = str.begin(), end = str.end();

        qi::rule<std::string::const_iterator, std::string()> double_quoted_string
            = '"' >> *("\"\"" >> qi::attr('"') | ~qi::char_('"')) >> '"';

        std::string ut;
        bool r = qi::phrase_parse(iter, end, double_quoted_string >> qi::eoi, qi::blank, ut);

        std::cout << str << " ";
        if (r) {
            std::cout << "OK: " << std::quoted(ut, '\'') << "\n";
        }
        else {
            std::cout << "Failed\n";
        }
        if (iter != end) {
            std::cout << "Remaining unparsed: " << std::quoted(std::string(iter, end)) << "\n";
        }
        std::cout << "----\n";
    }
}

Печать

 "hello"  OK: 'hello'
----
    "  hello "  OK: '  hello '
----
  "  hello ""escaped"" "   OK: '  hello "escaped" '
----
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...