Токенизируйте строку, исключая разделители внутри кавычек

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

Мне нужно извлечь все токены, исключая кавычки (для указанных), используя регулярное выражение boost.

Я думаю, что мне нужно использовать следующее выражение:

sregex pattern = sregex::compile("\"(?P<token>[^\"]*)\"|(?P<token>\\S+)");

Но я получаю ошибку:

именная марка уже существует

Решение, опубликованное для C#, похоже, работает с дубликатом именованной метки, учитывая, что это выражение OR с другим.

Регулярное выражение для разделения на пробелы, кроме как в кавычках

3 ответа

Решение

Я ответил на очень похожий вопрос здесь:

Как заставить мой сплит работать только на одной реальной строке и быть способным пропускать процитированные части строки?

Пример кода

  • использует Boost Spirit
  • поддерживает строки в кавычках, поля в кавычках, определяемые пользователем разделители, экранированные кавычки
  • поддерживает много (разнообразных) выходных контейнеров в целом
  • поддерживает модели концепции Range в качестве входных данных (включая char[], например)

Протестировано с относительно широким диапазоном версий компилятора и версий Boost.

https://gist.github.com/bcfbe2b5f071c7d153a0

Большинство разновидностей регулярных выражений не позволяют повторно использовать имена групп. Некоторые ароматы позволяют это, если все варианты использования находятся в одном и том же чередовании, но, очевидно, ваше использование не относится к их числу Однако, если вы используете достаточно свежую версию Boost, вы сможете использовать группу сброса ветви. Это выглядит так - (?|...|...|...) - и в каждой альтернативе нумерация групп сбрасывается туда, где она была до того, как была достигнута группа сброса ветви. Он также должен работать с именованными группами, но это не гарантировано. Я не в состоянии проверить это сам, поэтому попробуйте это:

"(?|\"(?P<token>[^\"]*)\"|(?P<token>\\S+))"

... и если это не сработает, попробуйте это с простыми старыми пронумерованными группами.

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

Вот код, который работал для меня:

    #include <boost/xpressive/xpressive.hpp>
    using namespace boost::xpressive;
...
    std::vector<std::string> tokens;
    std::string input = "here is a \"test string\"";
    sregex pattern = sregex::compile("\"(?P<quoted>[^\"]*)\"|(?P<unquoted>\\S+)");
    sregex_iterator cur( input.begin(), input.end(), pattern );
    sregex_iterator end;

    while(cur != end)
    {
      smatch const &what = *cur;
      if(what["quoted"].length() > 0)
      {
        tokens.push_back(what["quoted"]);
      }
      else
      {
        tokens.push_back(what["unquoted"]);
      }
      cur++;
    }
Другие вопросы по тегам