Как разобрать CSV с кавычками, разграничивающими поля в C? - PullRequest
2 голосов
/ 16 февраля 2011

Учтите, это сообщение:

N,8545,01/02/2011 09:15:01.815,"RASTA OPTSTK 24FEB2011 1,150.00 CE",S,8.80,250,0.00,0

Это всего лишь пример.Идея в том, что это одна из строк в CSV-файле.Теперь, если я хочу разбить его на запятые, то возникнет проблема с цифрой 1150.

Строка внутри двойных кавычек имеет переменную длину, но может быть определена как один «элемент» (если я могу использовать термин). Другие элементы - это те, которые разделены,

Какмне разобрать это?(кроме разбора Ragel)

Сохам

Ответы [ 4 ]

4 голосов
/ 16 февраля 2011

Разбейте строку на поля, разделенные запятыми при условии , что запятые не вставлены в строки в кавычках.

Быстрый способ сделать это - использовать конечный автомат.

boolean inQuote = false;
StringBuffer buffer= new StringBuffer();
// readchar() is to be implemented however you read a char
while ((char = readchar()) != -1) {
  switch (char) {

    case ',':
      if (inQuote == false) {
         // store the field in our parsedLine object for later processing.
         parsedLine.addField(buffer.toString());
         buffer.setLength(0);
      }
      break;

    case '"': 
      inQuote = !inQuote;
      // fall through to next target is deliberate.

    default:
      buffer.append(char);

  }
}

Обратите внимание, что, хотя это и является примером, CSV-файлам нужно учесть немного больше (например, встроенные кавычки в кавычках или целесообразность удаления внешних кавычек в вашем примере).

1 голос
/ 16 февраля 2011

Быстрое и грязное решение, если вы не хотите добавлять внешние библиотеки, заключалось бы в преобразовании двойных кавычек в \ 0 (маркер конца строки), а затем в разбор трех строк по отдельности с использованием sscanf. Ужасно, но должно работать.

Предполагая, что входные данные правильно сформированы (в противном случае вам придется добавить обработку ошибок):

for (i=0; str[i]; i++)
  if (str[i] == '"') str[i] = 0;
str += sscanf(str, "%c,%d,%d/%d/%d %d:%d:%d.%d,", &var1, &var2, ..., &var9);
var10 = str; // it may be str+1, I don't remember if sscanf consumes also the \0
sscanf(str+strlen(var10), ",%c,%f,%d,%f,%d", &var11, &var12, ..., &var15);

Вам, очевидно, придется сделать копию var10, если вы хотите немедленно освободить str.

0 голосов
/ 16 февраля 2011

Как насчет libcsv от нашего собственного Роберта Гэмбла ?

0 голосов
/ 16 февраля 2011

Это функция для получения следующего отдельного поля CSV из входного файла, поставляемого как FILE *.Он ожидает, что файл будет открыт в текстовом режиме, и поддерживает кавычки со встроенными кавычками и символами новой строки.Поля, длина которых превышает размер предоставленного буфера, усекаются.

int get_csv_field(FILE *f, char *buf, size_t size)
{
    char *p = buf;
    int c;
    enum { QS_UNQUOTED, QS_QUOTED, QS_GOTQUOTE } quotestate = QS_UNQUOTED;

    if (size < 1)
        return EOF;

    while ((c = getc(f)) != EOF)
    {
        if ((c == '\n' || c == ',') && quotestate != QS_QUOTED)
            break;

        if (c == '"')
        {
            if (quotestate == QS_UNQUOTED)
            {
                quotestate = QS_QUOTED;
                continue;
            }

            if (quotestate == QS_QUOTED)
            {
                quotestate = QS_GOTQUOTE;
                continue;
            }

            if (quotestate == QS_GOTQUOTE)
            {
                quotestate = QS_QUOTED;
            }
        }

        if (quotestate == QS_GOTQUOTE)
        {
            quotestate = QS_UNQUOTED;
        }

        if (size > 1)
        {
            *p++ = c;
            size--;
        }
    }

    *p = '\0';

    return c;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...