Как разобрать файл .csv с кавычками в C - PullRequest
0 голосов
/ 01 февраля 2019

Допустим, строка, которую я пытаюсь разобрать, читает:

"Смит, Джон", Данные1, Данные2, Данные3

Я также могу получить строки, которые читают

Дейв, Данные1, Данные2, Данные3

, поэтому у меня есть оператор if

строка - это строка текста fgets() 'd из файла,но я думаю, что это работает

Остальные, с которыми я боролся около часа или около того.Я пытаюсь переформатировать «Смит, Джон», чтобы он был Джоном Смитом, а затем назначить его для recTemp.artist

if (line[0] == '\"') {
    //Read the last name, first name",
    char lastTemp[30] = "";
    char firstTemp[30] = "";
    strcpy(lastTemp , strtok(line, ", "));
    strcpy(firstTemp, strtok(NULL, "\","));
    char * t;
    t = strstr(lastTemp, "\"");
    strcpy(t, " ");
    //Concatenate each string assign to the artist value
    strcat(firstTemp, lastTemp);
    strcpy(recTemp.artist, firstTemp);
}

. Я думаю, что ошибка возникает из-за вызова strstr или strcpy сразу после него, ноЯ не уверен

Спасибо!

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Если вы хотите избежать изменения line с помощью strtok, вы можете просто использовать арифметику указателя для копирования либо "first last" в recTemp.artist, либо скопировать "name" в случае, когда в первом нет кавычекполе.Это просто другой подход, который позволяет избежать изменения исходной строки.(и полезное упражнение в использовании указателей)

В случае, когда присутствуют кавычки, вы можете установить указатель (p) на line + 1 и использовать strstr, чтобы найти параметр подстроки "\","указатель конца (endptr) на закрывающую кавычку.Затем можно позвонить strchar на p с помощью ',', чтобы найти запятую между last, first и установить другой указатель для перехода к началу имени (firstp).Как только вы наберете firstp, указывающее на начало имени, вы можете просто memcpy от имени до recTemp.artist, добавить space, а затем скопировать фамилию, заканчивая нулем после этого.

В случае отсутствия кавычек вам нужно всего лишь использовать strchr, чтобы найти ',' разделитель полей и вызвать memcpy, а затем nul-terminate.

Краткий пример:

#include <stdio.h>
#include <string.h>

typedef struct {
    char artist[64];
} rec_t;

int main (void) {
#ifndef NOQUOTE    
    char line[] = "\"Smith, John\",Data1,Data2,Data3";
#else
    char line[] = "Dave,Data1,Data2,Data3";
#endif
    rec_t recTemp;

    if (*line == '\"') {    /* if double-quotes are present */
        char *p = line + 1, *endptr, *sep;    /* ptr, endptr & sep */
        if (!(endptr = strstr (p, "\","))) {  /* find close quote, validate */
            fputs ("error: invalid line format.\n", stderr);
            /* handle error as needed, e.g. */
            return 1;
        }

        if ((sep = strchr (p, ','))) {        /* locate ',' in last, first */
            char *firstp = sep + 1;           /* set firstp to next char */
            while (*firstp && *firstp == ' ') /* skip any leading spaces */
                firstp++;
            memcpy (recTemp.artist, firstp, endptr - firstp); /* copy first */
            endptr = recTemp.artist + (endptr-firstp);  /* set endptr after */
            *endptr++ = ' ';                  /* add a space */
            memcpy (endptr, p, sep - p);      /* copy last */
            *(endptr + (sep - p)) = 0;        /* nul-terminate */
        }
    }
    else {  /* otherwise - name without quotes */
        char *sep = strchr (line, ',');       /* find field seperator */
        if (!sep) {
            fputs ("error: invalid line format.\n", stderr);
            /* handle error as needed, e.g. */
            return 1;
        }
        memcpy (recTemp.artist, line, (sep - line));  /* copy name */
        *(recTemp.artist + (sep - line)) = 0; /* nul-terminate */
    }

    printf ("recTemp.artist: '%s'\n", recTemp.artist);
}

Пример использования / Вывод

$ ./bin/rectmp
recTemp.artist: 'John Smith'

Случай без кавычек, скомпилированный с -DNOQUOTE:

$ ./bin/rectmpnq
recTemp.artist: 'Dave'

Используете ли вы strtok или пройдите несколько указателей вниз line, оба в порядке.Если вы хотите сохранить line без изменений, то либо сделайте копию, прежде чем работать с ней с помощью strtok, либо просто используйте арифметику указателей.Вы можете сбросить сборку, сгенерированную в обоих методах, чтобы увидеть, обеспечивает ли ваш компилятор преимущество в оптимизации между методами.Разница будет незначительной в великой схеме вещей.

0 голосов
/ 01 февраля 2019

Чтобы ответить на ваш вопрос:

"Я пытаюсь переформатировать" Смит, Джон ", чтобы его Джон Смит"

Если не использовать регулярные выражения для извлечения цитат из строки, я бы сделал следующее:

#include <iostream>
#include <cstring>
#include <stdio.h>

int main() {
    char line[100] = "\"Smith,John\",Data1,Data2,Data3";
    // fgets(line, 100, stdin);
    char* name = strtok(line, "\"");
    char *substring2 = strtok(NULL, "\"");
    char* LastName = strtok(name, ",");
    char* FirstName = strtok(NULL, ",");

    char result[100];
    strcpy(result, FirstName);
    strcat(result, ",");
    strcat(result, LastName);
    strcat(result, substring2);
    printf("%s",result);

}

, который выдает результат:

Джон, Смит, Данные1, Данные2, Данные3

...