Russian Qt Forum

Qt => Общие вопросы => Тема начата: xintrea от Сентябрь 19, 2016, 11:59



Название: [Решено] Чем бы разбить строку с учетом кавычек?
Отправлено: xintrea от Сентябрь 19, 2016, 11:59
Задача: нужно выделить в строке подстроки, ограничивающиеся символами-разделителями. Но есть некоторые тонкости:

- Символы-разделители могут быть разные. Примерный набор: " .,;:-?!/\".
- В строках могут встречаться кавычки. Все что заключено между двумя кавычками - это отдельная подстрока, и символы-разделители в ней остаются как есть (то есть, разбивки внутри таких подстрок делать не нужно, «схлопывать» символы-разделители тоже в таких подстроках ненужно).
- В исходной строке подстрок в кавычках может быть несколько.
- Если кавычек нечетное количество, выделяются подстроки в парных кавычках, и подстрокой считается часть строки со следующего знакосимвола после последней кавычки до конца строки.

Решение нужно с поддержкой кириллицы (UTF-8) для использования в опенсорчной кроссплатформенной Qt-only программе (минимум Linux, Windows, MacOS, FreeBSD, Android). Поэтому что-то наподобе re2c рассматриваю только в том случае, если есть готовое решение по интеграции библиотеки в код программы.


Примеры, как должно работать разбиение:

Код:
0. Строка: Один два, три
Один
два
три

1. Строка: Один, два, три
Один
два
три

2. Строка: Один-два, три
Один
два
три

3. Строка: "Один два" три
Один два
три

4. Строка: "Один-два" три
Один-два
три

5. Строка: "Один-два" "три четыре
Один-два
три четыре

6. Строка: "Один-два" три, "четыре
Один-два
три
четыре

7. Строка: "Один-два" три "четыре! пять"
Один-два
три
четыре! пять


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: gil9red от Сентябрь 19, 2016, 12:05
Придется писать самому, не думаю что аналогичные парсеры найдутся в каких-то библиотеках -- формат самописный


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: m_ax от Сентябрь 19, 2016, 12:08
Посмотрите на boost::tokenizer, boost::xpressive, boost::spirit.


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: qate от Сентябрь 19, 2016, 12:35
1. регуляркой найти в сроке "окавыченные" строки и добавить их в итоговый QStringList
2. вырезать их из исходной строки 
3. по оставшейся строке пройти посимвольно, разрезая её по разделителям и добавляя их в итоговый QStringList


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: __Heaven__ от Сентябрь 19, 2016, 13:07
QString::split("\"") и обрабатывать каждую вторую строку, бугага :D


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: Igors от Сентябрь 19, 2016, 13:55
Мой велик (http://www.prog.org.ru/index.php?topic=22338.msg156798#msg156798)


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: m_ax от Сентябрь 19, 2016, 14:08
boost::tokenizer - всего пара строк:

Код
C++ (Qt)
#include <iostream>
#include <string>
#include <boost/tokenizer.hpp>
 
 
using namespace std;
using namespace boost;
 
int main()
{
   string str = "Один-два три, четыре, \"четыре с половиной\"  пять \"шесть, семь восемь";
 
   tokenizer<escaped_list_separator<char>> tok(str, escaped_list_separator<char>("\\", ", -", "\""));
   for(auto it = tok.begin(); it != tok.end(); ++it)
       cout << *it << endl;
 
   return 0;
}
 


Название: Re: Чем бы разбить строку с учетом кавычек?
Отправлено: xintrea от Сентябрь 20, 2016, 10:50
Придется писать самому, не думаю что аналогичные парсеры найдутся в каких-то библиотеках -- формат самописный

Все решилось проще, через конечный автомат:

Код:
QStringList FindScreen::textDelimiterDecompose(QString text)
{
  const int len=text.length();

  QStringList list;
  QString buf;
  bool quoted=false;

  QString delimiter=" '.,;:-?!`";
  delimiter.append(QChar::Tabulation);
  delimiter.append(QChar::Nbsp);

  for(int i=0; i<len; i++)
  {
    // Если обнаружен разделитель
    if(delimiter.contains( text[i] ))
    {
      if( !quoted )
      {
        if(buf.length() > 0)
        {
          list.append(buf);
          buf = "";
        }
      }
      else
        buf += text[i];
    }
    else if(text[i] == '"')
      quoted = !quoted;
    else
      buf += text[i];
  }

  if(buf.length() > 0)
    list.append(buf);

  qDebug() << "Find split list:" << list;

  return list;
}

Все тесты из стартовой мессаги проходят как задумано.