如何在C

时间:2019-02-01 06:42:19

标签: c string csv quotation-marks

让我们说我正在尝试解析的字符串为

  

“史密斯,约翰”,Data1,Data2,Data3

我还可以得到读为

的行
  

Dave,Data1,Data2,Data3

所以我有if语句

line是文件中fgets()的文本行,但是我认为这行得通

其余的我现在已经挣扎了大约一个小时左右。我正在尝试重新格式化“史密斯·约翰”,以便将其改成约翰·史密斯,然后将其分配给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 :(得分:0)

回答您的问题:

  

“我正在尝试重新格式化“约翰·史密斯”,以便重新命名为“约翰·史密斯””

使用正则表达式从字符串中提取引号的方法简短,我将执行以下操作,

#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);

}

产生输出:

  

John,Smith,Data1,Data2,Data3

答案 1 :(得分:0)

如果要避免用line更改strtok,则可以简单地使用指针算法将"first last"复制到recTemp.artist,或将"name"复制到第一个字段中没有引号的情况。这只是避免修改原始字符串的另一种方法。 (以及使用指针的健康锻炼)

如果存在引号,则可以将指针(p)设置为line + 1,然后使用strstr查找子字符串"\","并设置结束指针( endptr)。然后,您可以使用strcharp上调用',',以找到last, first之间的逗号,并设置另一个指针以前进到名字的开头(firstp )。一旦firstp指向名字的开头,您就可以将memcpy的名字命名为recTemp.artist,添加space,然后复制姓氏,在此之后终止。

在不加引号的情况下,您只需使用strchr来找到','字段分隔符并调用memcpy,然后以nul终止。

一个简短的例子是:

#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对副本进行操作之前进行复制,或者仅使用指针算法。您可以转储在两个方法上生成的程序集,以查看编译器是否在两个方法之间提供了优化优势。在事物的宏伟计划中,这种差异可以忽略不计。