天道酬勤,学无止境

如何在支持空字段的同时使用 sscanf 解析逗号分隔字符串中的字段?(How do I parse out the fields in a comma separated string using sscanf while supporting empty fields?)

问题

我有一个逗号分隔的字符串,它可能包含空字段。 例如:

1,2,,4

使用基本

sscanf(string,"%[^,],%[^,],%[^,],%[^,],%[^,]", &val1, &val2, &val3, &val4);

我得到了空字段之前的所有值,以及从空字段开始的意外结果。

当我从 sscanf() 中删除空字段的表达式时,

sscanf(string,"%[^,],%[^,],,%[^,],%[^,]", &val1, &val2, &val3, &val4);

一切正常。

由于我不知道什么时候会得到一个空字段,有没有办法重写表达式以优雅地处理空字段?

回答1

如果您使用带有逗号的strtok作为分隔符,您将获得一个字符串列表,其中一个或多个字符串的长度为空/零。

在这里查看我的答案以获取更多信息。

回答2

男子 sscanf:

[匹配指定的一组接受字符中的非空字符序列;

(强调)。

回答3

这看起来您目前正在处理 CSV 值。 如果您需要扩展它来处理带引号的字符串(例如,这样字段可以包含逗号),您会发现scanf -family 无法处理格式的所有复杂性。 因此,您将需要使用专门设计用于处理(您的变体)CSV 格式的代码。

您将在“编程实践”中找到关于一组 CSV 库实现的讨论 - 在 C 和 C++ 中。 毫无疑问,还有很多其他可用的。

回答4

这是我扫描逗号分隔的 int 值的版本。 该代码检测空字段和非整数字段。

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

int main(){
  char str[] = " 1 , 2 x, , 4 ";
  printf("str: '%s'\n", str );

  for( char *s2 = str; s2; ){
    while( *s2 == ' ' || *s2 == '\t' ) s2++;
    char *s1 = strsep( &s2, "," );
    if( !*s1 ){
      printf("val: (empty)\n" );
    }
    else{
      int val;
      char ch;
      int ret = sscanf( s1, " %i %c", &val, &ch );
      if( ret != 1 ){
        printf("val: (syntax error)\n" );
      }
      else{
        printf("val: %i\n", val );
      }
    }
  }

  return 0;
}

结果:

str: ' 1 , 2 x, , 4 '
val: 1
val: (syntax error)
val: (empty)
val: 4
回答5

在 '%' 后放置一个 '*' 以跳过阅读。 此外,例如,可以仅读取 3 个字符,注意 '%3s'。

回答6

我来到这里寻找同一问题的答案。 我也不想留下 scanf 函数。 最后,我自己构建了一个 zsscanf,在那里我解析了格式,对每个数据进行了一个一个的 sscanf,并检查了 sscanf 的返回以查看是否有任何读取为空。 这在某种程度上是我的特殊情况:我只想要一些字段,其中一些可能是空的,并且不能假设分隔符。

#include <stdarg.h>
#include <stdio.h>

int zsscanf(char *data, char *format, ...)
{
    va_list argp;
    va_start(argp, format);
    int fptr = 0, sptr = 0, iptr = 0, isptr = 0, ok, saved = 0;
    char def[32];
    while (1)
    {
        if (format[fptr] != '%')
        {
            ok = sscanf(&format[fptr], "%28[^%]%n", def, &iptr);
            if (!ok) break;
            fptr += iptr;
            def[iptr] = '%';
            def[iptr+1] = 'n';
            def[iptr+2] = 0;
            ok = sscanf(&data[sptr], def, &isptr);
            if (!ok) break;
            sptr += isptr;
        }
        else
            if (format[fptr+1] == '%')
            {
                if (data[sptr] == '%')
                {
                    fptr += 2;
                    sptr += 1;
                }
                else
                {
                    ok = -1;
                    break;
                }
            }
            else
            {
                void *savehere = NULL;
                ok = sscanf(&format[fptr], "%%%28[^%]%n", &def[1], &iptr);
                if (!ok) break;
                fptr += iptr;
                def[0] = '%';
                def[iptr] = '%';
                def[iptr+1] = 'n';
                def[iptr+2] = 0;
                isptr = 0;
                if (def[1] != '*')
                {
                    savehere = va_arg(argp, void*);
                    ok = sscanf(&data[sptr], def, savehere, &isptr);
                    if (ok == 0 && isptr == 0)
                    {
                        // Let's assume only char types. Won't hurt in other cases.
                        ((char*)savehere)[0] = 0;
                        ok = 1;
                    }
                    if (ok > 0)
                    {
                        saved++;
                    }
                }
                else
                {
                    ok = sscanf(&data[sptr], def, &isptr) == 0;
                }
                if (ok < 0) break;
                sptr += isptr;
            }
    }
    va_end(argp);
    return saved == 0 ? ok : saved;
}

int main()
{
    char *format = "%15[^\t;,]%*1[\t;,]" // NameId
                   "%*[^\t;,]%*1[\t;,]" // Name
                   "%*[^\t;,]%*1[\t;,]" // Abbreviation
                   "%*[^\t;,]%*1[\t;,]" // Description
                   "%31[^\t;,]"; // Electrical Line
    char nameId[16];
    char elect[32];
    char *line1 = "TVC-CCTV-0002\tTVC-CCTV-0002\tTVC-CCTV-0002\tCCTV DOMO CAMERA 21-32-29\tELECTRICAL_TopoLine_823\tfoo\tbar";
    char *line2 = "TVC-CCTV-0000;;;;;foo;bar;";

    int ok = zsscanf(line1, format, nameId, elect);
    printf ("%d: |%s|%s|\n", ok, nameId, elect);
    ok = zsscanf(line2, format, nameId, elect);
    printf ("%d: |%s|%s|\n", ok, nameId, elect);
    return 0;
}

输出:

    2: |TVC-CCTV-0002|ELECTRICAL_TopoLine_823|
    2: |TVC-CCTV-0000||

请注意,它没有经过全面测试并且有严重的限制(最明显的限制:只接受%...s%...c%...[...]并且需要分隔符为%...[...] ; 否则我真的不得不关心格式字符串,这样我只关心% )。

回答7

我不得不稍微修改一下这段代码才能正常工作:

//rm token_pure;gcc -Wall -O3 -o token_pure token_pure.c; ./token_pure 
#include <stdio.h>
#include <string.h>

int main ()
{
    char str[] = " 1 , 2 x, , 4 ";
    char *s1;
    char *s2;
    s2=(void*)&str; //this is here to avoid warning of assignment from incompatible pointer type 
        do {
            while( *s2 == ' ' || *s2 == '\t' )  s2++;
            s1 = strsep( &s2, "," );
            if( !*s1 ){
                printf("val: (empty)\n" );
            }
            else{
                int val;
                char ch;
                int ret = sscanf( s1, " %i %c", &val, &ch );
                if( ret != 1 ){
                    printf("val: (syntax error)\n" );
                }
                else{
                    printf("val: %i\n", val );
                }
            }
        } while (s2!=0 );
        return 0;
    }

和输出:

val: 1
val: (syntax error)
val: (empty)
val: 4
回答8

我对制表符分隔的 TSV 文件进行了修改,希望它可以帮助:

//rm token_tab;gcc -Wall -O3 -o token_tab token_tab.c; ./token_tab 
#include <stdio.h>
#include <string.h>

int main ()
{
//  char str[] = " 1     2 x         text   4 ";
    char str[] = " 1\t 2 x\t\t text\t4 ";
    char *s1;
    char *s2;
    s2=(void*)&str; //this is here to avoid warning of assignment from incompatible pointer type 
        do {
            while( *s2 == ' ')  s2++;
            s1 = strsep( &s2, "\t" );
            if( !*s1 ){
                printf("val: (empty)\n" );
            }
            else{
                int val;
                char ch;
                int ret = sscanf( s1, " %i %c", &val, &ch );
                if( ret != 1 ){
                    printf("val: (syntax error or string)=%s\n", s1 );
                }
                else{
                    printf("val: %i\n", val );
                }
            }
        } while (s2!=0 );
        return 0;
    }

和输出:

val: 1
val: (syntax error or string)=2 x
val: (empty)
val: (syntax error or string)=text
val: 4
回答9

这里列出的strtok()存在一些问题:http://benpfaff.org/writings/clc/strtok.html

因此,最好避免 strtok

现在,考虑一个包含空字段的字符串,如下所示:

char myCSVString[101] = "-1.4,2.6,,-0.24,1.26"; // specify input here

您可以使用简单的函数将 CSV 格式的字符串转换为浮点数组

int strCSV2Float(float *strFloatArray , char *myCSVStringing);

请在下面找到用法

#include <stdio.h>
#include <stdlib.h>



int strCSV2Float(float *strFloatArray , char *myCSVStringing);

  void main()
 {

    char myCSVString[101] = "-1.4,2.6,,-0.24,1.26"; // specify input here
    float floatArr[10]; // specify size here 
    int totalValues = 0;

    printf("myCSVString == %s \n",&myCSVString[0]);

    totalValues = strCSV2Float(&floatArr[0] , &myCSVString[0]); // call the function here 

    int floatValueCount = 0;

    for (floatValueCount = 0 ; floatValueCount < totalValues ; floatValueCount++)
    {

      printf("floatArr[%d] = %f\n",floatValueCount , floatArr[floatValueCount]);

    }

 }




int strCSV2Float(float *strFloatArray , char *myCSVStringing)
{

int strLen = 0;
int commaCount =0; // count the number of commas
int commaCountOld =0; // count the number of commas
int wordEndChar = 0;
int wordStartChar = -1;
int wordLength =0;


   for(strLen=0; myCSVStringing[strLen] != '\0'; strLen++) // first get the string length
   {

       if ( (myCSVStringing[strLen] == ',')  || ( myCSVStringing[strLen+1] == '\0' ))
        {
           commaCount++;
           wordEndChar = strLen;
        }
       if ( (commaCount - commaCountOld) > 0 )
        {
          int aIter =0;
          wordLength = (wordEndChar - wordStartChar);
          char word[55] = "";
          for (aIter = 0;  aIter < wordLength; aIter++)
          {
            word[aIter] = myCSVStringing[strLen-wordLength+aIter+1];
          }

          if (word[aIter-1] == ',') 
           word[aIter-1] = '\0';

          //  printf("\n");
          word[wordLength] = '\0';
          strFloatArray[commaCount-1] = atof(&word[0]);

          wordLength = 0;
          wordStartChar = wordEndChar;
          commaCountOld = commaCount;

        }  
  }

  return commaCount;

}

输出如下:

myCSVString == -1.4,2.6,,-0.24,1.26 
floatArr[0] = -1.400000
floatArr[1] = 2.600000
floatArr[2] = 0.000000
floatArr[3] = -0.240000
floatArr[4] = 1.260000
回答10

scanf()返回分配的项目数。 也许你可以使用这些信息......

char *data = "1, 2,,, 5, 6";
int a[6];
int assigned = sscanf(data, "%d,%d,%d,%d,%d,%d", a, a+1, a+2, a+3, a+4, a+5);
if (assigned < 6) {
    char fmt[18];
    switch (assigned) {
        default: assert(0 && "this did not happen"); break;
        case 0: fmt = ",%d,%d,%d,%d,%d"; break;
        case 1: fmt = "%d,,%d,%d,%d,%d"; break;
        case 2: fmt = "%d,%d,,%d,%d,%d"; break;
        case 3: fmt = "%d,%d,%d,,%d,%d"; break;
        case 4: fmt = "%d,%d,%d,%d,,%d"; break;
        case 5: fmt = "%d,%d,%d,%d,%d,"; break;
    }
    sscanf(data, fmt, a+(assigned<=0), a+1+(assigned<=1), a+2+(assigned<=2),
                      a+3+(assigned<=3), a+4+(assigned<=4));
}

啊! 这仅适用于 1 个缺失值
正如其他答案所指出的那样,您最好以“通常”的方式解析字符串: fgets()strtok()

回答11

如果输入字符串没有嵌入空格,也没有嵌入空格,伪代码:扫描字符串,用' '替换逗号; 使用格式参数 &s 跟进 sscanf

... char inputstring[]="this,is,a,parameter,string"; 转换后,到' '

char inputstring[]="这是一个参数字符串";

int i=sscanf(inputstring,"&s&s&s&s&s",ptr1,ptr2,ptr3,ptr4,ptr5);

其中 i=4 和 ptr1 有“this”,ptr5 有“strong”。

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 如何解析以逗号分隔的字符串? [复制](How to parse a string separated by commas? [duplicate])
    问题 这个问题在这里已经有了答案: 如何在支持空字段的同时使用 sscanf 解析逗号分隔字符串中的字段? (11 个回答) 8 年前关闭。 Char *strings = "1,5,95,255" 我想将每个数字存储到一个 int 变量中,然后将其打印出来。 例如输出变成这样。 值 1 = 1 值 2 = 5 值 3 = 95 值 4 = 255 我想在循环中执行此操作,因此如果字符串中有 4 个以上的值,我应该能够获得其余的值。 我想看看这个例子。 我知道这对你们中的许多人来说是非常基础的,但我觉得这有点挑战。 谢谢 回答1 修改自 cplusplus strtok示例: #include <stdio.h> #include <string.h> #include <stdlib.h> int main () { char str[] ="1,2,3,4,5"; char *pt; pt = strtok (str,","); while (pt != NULL) { int a = atoi(pt); printf("%d\n", a); pt = strtok (NULL, ","); } return 0; } 回答2 我不知道上面评论中提到的功能,但要按照您要求的方式做您想做的事情,我会尝试此操作或类似的操作。 char *strings = "1,5,95,255"
  • 我可以用什么代替scanf进行输入转换?(What can I use for input conversion instead of scanf?)
    问题 我经常看到人们不鼓励其他人使用scanf并说有更好的选择。 但是,我最终看到的只是“不要使用scanf ”或“这里是正确的格式字符串” ,而且从来没有提到任何“更好的选择”的示例。 例如,让我们看一下这段代码: scanf("%c", &c); 这将读取最后一次转换后留在输入流中的空白。 通常建议的解决方案是使用: scanf(" %c", &c); 或不使用scanf 。 由于scanf不好,在不使用scanf情况下转换scanf通常可以处理的输入格式(例如整数,浮点数和字符串)的ANSI C选项有哪些? 回答1 读取输入的最常见方式是: 使用固定大小的fgets (通常建议这样做),以及使用fgetc ,如果您只阅读一个char ,这可能很有用。 要转换输入,可以使用多种功能: strtoll ,将字符串转换为整数 strtof / d / ld ,将字符串转换为浮点数 sscanf ,虽然不像下面提到的大多数缺点,但它并不像使用scanf那样糟糕在普通的ANSI C中,没有很好的方法来解析以分隔符分隔的输入。要么使用POSIX的strtok_r ,要么使用strtok ,这不是线程安全的。 您还可以使用strcspn和strspn来滚动自己的线程安全变体,因为strtok_r不涉及任何特殊的OS支持。 可能有些矫kill过正,但是您可以使用词法分析器和解析器(
  • 在不受全局语言环境影响的情况下有效地从字符串中读取括号中的两个逗号分隔的浮点数(Efficiently reading two comma-separated floats in brackets from a string without being affected by the global locale)
    问题 我是一个库的开发人员,我们的旧代码使用sscanf()和sprintf()从/向字符串读取/写入各种内部类型。 我们遇到了使用我们的库的用户的问题,他们的语言环境与我们基于 XML 文件的语言环境(“C”语言环境)不同。 在我们的例子中,这会导致从这些 XML 文件中解析出的值不正确,以及在运行时作为字符串提交的值。 区域设置可以由用户直接更改,但也可以在用户不知情的情况下更改。 如果语言环境更改发生在另一个库中,例如 GTK,这是​​一个错误报告中的“肇事者”,就会发生这种情况。 因此,我们显然希望从语言环境中删除任何依赖项,以永久摆脱这些问题。 我已经在 float/double/int/... 的上下文中阅读了其他问题和答案,特别是如果它们由字符分隔或位于括号内,但到目前为止,我发现的建议解决方案并不令我们满意。 我们的要求是: 不依赖于标准库以外的库。 例如,使用 boost 中的任何东西都不是一种选择。 必须是线程安全的。 这特别是关于可以全局更改的语言环境。 这对我们来说真的很糟糕,因为我们库的一个线程可能会受到用户程序中另一个线程的影响,该线程也可能正在运行一个完全不同库的代码。 因此,任何受setlocale()直接影响的东西都不是一种选择。 此外,由于线程中的竞争条件,在开始读/写之前设置语言环境并将其设置回原始值也不是解决方案。 虽然效率不是最重要的(#1
  • C 使用 scanf() for | 分隔字符串(C using scanf() for | delimited string)
    问题 我想输入几个字符串然后输入两个整数。 虽然字符串由“|”分隔,但整数由“.”分隔。 在网上环顾四周,我看到了某种涉及[^]的语法。 我正在使用它,但它根本不起作用。 有人可以指出我应该做什么以及为什么我做的事情是错误的吗? sscanf(str, "%s[^|],%s[^|],%s[^|],%i[^|],%i[^.]", …); 回答1 语法充其量是神秘的 - 我建议使用不同的方法,例如strtok() ,或使用字符串处理函数strchr()等进行解析。 但是,您必须意识到的第一件事是%[^<delimiter-list>]格式说明符(行话中的“扫描集”,由 POSIX scanf() 在许多其他地方记录)仅提取字符串字段 - 您必须将提取的字符串转换为整数(如果它们代表的是整数)。 其次,您仍然必须将分隔符作为文字匹配字符包含在格式说明符之外——您已经用逗号分隔格式说明符,其中| 在输入流中。 考虑以下: #include <stdio.h> int main() { char a[32] ; char b[32] ; char c[32] ; char istr[32] ; // Buffer for string representation of i int i ; int j ; // j can be converted directly as it is at
  • 使用 python 解析 CSV 文件(稍后制作决策树)[关闭](Parse a CSV file using python (to make a decision tree later) [closed])
    问题 就目前而言,这个问题不适合我们的问答形式。 我们希望答案得到事实、参考或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。 如果您认为此问题可以改进并可能重新打开,请访问帮助中心以获取指导。 9年前关闭。 首先,全面披露:这是一个 uni 任务,所以我不想收到代码。 :)。 我更在寻找方法; 我对 python很陌生,读过一本书但还没有写任何代码。 整个任务是导入 CSV 文件的内容,根据 CSV 文件的内容创建决策树(使用 ID3 算法),然后解析第二个 CSV 文件以针对该树运行。 有一个很大的(可以理解的)偏好让它能够处理不同的 CSV 文件(我问我们是否被允许对列名进行硬编码,主要是为了消除它的可能性,答案是否定的)。 CSV 文件采用相当标准的格式; 标题行用 # 标记,然后显示列名,之后的每一行都是一系列简单的值。 例子: # Column1, Column2, Column3, Column4 Value01, Value02, Value03, Value04 Value11, Value12, Value13, Value14 目前,我正在尝试解决第一部分:解析 CSV。 要为决策树做出决策,字典结构似乎是最合乎逻辑的; 所以我想沿着这些方向做一些事情: Read in each line, character by character If
  • 如何在Bash中将字符串拆分为数组?(How to split a string into an array in Bash?)
    问题 在Bash脚本中,我想将一行分割成几部分并将它们存储在数组中。 例如,给出以下行: Paris, France, Europe 我想让结果数组看起来像这样: array[0] = Paris array[1] = France array[2] = Europe 一个简单的实现是可取的。 速度没关系。 我该怎么做? 回答1 IFS=', ' read -r -a array <<< "$string" 注意,在字符$IFS被单独视为分离器,使得在这种情况下,字段可以由逗号或空间而不是两个字符的序列中分离出来。 但是有趣的是,当逗号空间出现在输入中时,不会创建空字段,因为空格是经过特殊处理的。 要访问单个元素: echo "${array[0]}" 要遍历元素: for element in "${array[@]}" do echo "$element" done 要同时获取索引和值: for index in "${!array[@]}" do echo "$index ${array[index]}" done 最后一个示例很有用,因为Bash数组稀疏。 换句话说,您可以删除元素或添加元素,然后索引不连续。 unset "array[1]" array[42]=Earth 获取数组中元素的数量: echo "${#array[@]}" 如上所述,数组可以是稀疏的
  • 如何让 scanf 继续使用空扫描集(How to get scanf to continue with empty scanset)
    问题 我目前正在尝试使用以下格式解析 UnicodeData.txt:ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html 但是,当我尝试阅读时遇到了一个问题,请说如下一行。 something;123D;;LINE TABULATION; 我尝试通过如下代码从字段中获取数据。 问题是 fields[3] 没有被填充,并且 scanf 返回 2. in是当前行。 char fields[4][256]; sscanf(in, "%[^;];%[^;];%[^;];%[^;];%[^;];", fields[0], fields[1], fields[2], fields[3]); 我知道这是scanf()的正确实现,但是除了制作我自己的scanf() ,有没有办法scanf()起作用? 回答1 scanf不处理“空”字段。 所以你必须自己解析它。 以下解决方案是: 快,因为它使用strchr而不是相当慢的sscanf 灵活,因为它将检测任意数量的字段,最多可达给定的最大值。 函数parse从输入str提取字段,以分号分隔。 四个分号表示五个字段,其中部分或全部可以为空。 没有规定转义分号。 #include <stdio.h> #include <string.h> static int parse(char
  • 用 C# 中的复杂功能解析逗号分隔的字符串(Parse comma seperated string with a complication in C#)
    问题 我知道如何从昏迷分隔的字符串中获取子字符串,但这里有一个复杂的问题:如果子字符串包含昏迷怎么办。 如果子字符串包含逗号、换行符或双引号,则整个子字符串都用双引号封装。 如果子字符串包含双引号,则双引号会被另一个双引号转义。 最坏的情况是如果我有这样的事情: first,"second, second","""third"" third","""fourth"", fourth" 在这种情况下,子串是: 第一的第二,第二 “第三”第三 “第四”,第四 第二,第二是用双引号封装的,我不希望列表/数组中的那些双引号。 “第三个”第三个用双引号封装,因为它包含双引号,并且用附加的双引号转义。 同样,我不希望在列表/数组中封装双引号,并且我不希望双引号转义双引号,但我希望原始双引号是子字符串的一部分。 回答1 使用TextFieldParser一种方法: using (var reader = new StringReader("first,\"second, second\",\"\"\"third\"\" third\",\"\"\"fourth\"\", fourth\"")) using (var parser = new Microsoft.VisualBasic.FileIO.TextFieldParser(reader)) { parser.Delimiters =
  • sscanf() 和语言环境。 如何真正解析像“3.14”这样的东西?(sscanf() and locales. How does one really parse things like "3.14"?)
    问题 假设我必须读取一个包含一堆浮点数的文件。 数字可以像1e+10 、 5 、 -0.15等,即任何通用浮点数,使用小数点(这是固定的! )。 但是,我的代码是另一个应用程序的插件,我无法控制当前的语言环境。 例如,它可能是俄语,并且那里的 LC_NUMERIC 规则要求使用十进制逗号。 因此,Pi 应拼写为“3,1415...”,并且 sscanf("3.14", "%f", &x); 返回“1”,x 包含“3.0”,因为它拒绝解析超过 '.' 在字符串中。 我需要忽略此类数字解析任务的语言环境。 如何做到这一点? 我可以写一个 parseFloat 函数,但这似乎是一种浪费。 我还可以保存当前的语言环境,将其暂时重置为“C”,读取文件,然后恢复到保存的文件。 这对性能有什么影响? setlocale() 在某些 OS/libc 组合上可能会很慢,它到底在做什么? 另一种方法是使用 iostreams,但它们的性能同样不是很好。 所以我很困惑。 大家遇到这种情况怎么办? 干杯! 回答1 我个人的偏好是从不使用LC_NUMERIC ,即只用其他类别调用setlocale ,或者在用LC_ALL调用setlocale后,使用setlocale(LC_NUMERIC, "C"); . 否则,如果您想使用标准库以标准形式打印或解析数字以进行交换,那您就完全不走运了。
  • 处理CSV文件中的逗号(Dealing with commas in a CSV file)
    问题 我正在寻找有关如何处理正在创建的csv文件的建议,然后由我们的客户上传,并且该值可能带有逗号,例如公司名称。 我们正在研究的一些想法是:带引号的标识符(值“,”值“,”等)或使用|。 而不是逗号。 最大的问题是我们必须使其变得容易,否则客户将无法做到这一点。 回答1 正如其他人所说,您需要转义包含引号的值。 这是C♯中的一个小型CSV阅读器,它支持带引号的值,包括嵌入的引号和回车符。 顺便说一下,这是经过单元测试的代码。 我现在发布它是因为这个问题似乎很多,而且当简单的CSV支持可以解决时,其他人可能不希望有整个库。 您可以按以下方式使用它: using System; public class test { public static void Main() { using ( CsvReader reader = new CsvReader( "data.csv" ) ) { foreach( string[] values in reader.RowEnumerator ) { Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length ); } } Console.ReadLine(); } } 这是课程。 请注意,您也可以使用Csv.Escape函数编写有效的CSV。
  • 如何使用逗号分隔的字符串和逗号之间的(可能的)空字段按顺序拆分字符串[重复](How to split a string in order with a comma-separated string and (possible) empty fields between commas [duplicate])
    问题 这个问题在这里已经有了答案: 如何将逗号分隔的值转换为oracle中的行? (5 个回答) PL/SQL 逗号分隔列表; 删除重复项并放入数组2 个回答以逗号分隔的字符串列表 [重复] (2 个回答) Oracle- 拆分字符串逗号分隔(字符串包含空格和连续逗号) (4 个答案) 2年前关闭。 我需要在 Oracle PL/SQL 中以逗号分隔的顺序拆分字符串,包括空字段作为“none”值。 这是一个有 6 个字段的示例,但可以有更多或更少的字段 line varchar2(100) := "value1;value2;;;value5;value6;"; WITH test AS (SELECT line FROM DUAL) SELECT NVL(REGEXP_SUBSTR (line, '[^;]+', 1, ROWNUM),'none') as SPLIT FROM test CONNECT BY LEVEL <= LENGTH (REGEXP_REPLACE (line, '[^;]+')); 输出: value1 value2 value5 value6 none none 期望输出: value1 value2 none none value5 value6 回答1 with test as (select 'value1;value2;;;value5
  • 除了引号内的逗号之外,如何在 Python 中拆分逗号分隔的字符串(How do I split a comma delimited string in Python except for the commas that are within quotes)
    问题 我正在尝试在 python 中拆分逗号分隔的字符串。 对我来说,这里棘手的部分是数据中的一些字段本身有一个逗号,它们用引号( "或' )括起来。生成的拆分字符串也应该删除字段周围的引号。另外,一些字段可以为空。 例子: hey,hello,,"hello,world",'hey,world' 需要分成 5 个部分,如下所示 ['hey', 'hello', '', 'hello,world', 'hey,world'] 关于如何在 Python 中解决上述问题的任何想法/想法/建议/帮助将不胜感激。 谢谢你,维什 回答1 (编辑:由于re.findall工作方式,原始答案在边缘有空字段时遇到问题,因此我对其进行了一些重构并添加了测试。) import re def parse_fields(text): r""" >>> list(parse_fields('hey,hello,,"hello,world",\'hey,world\'')) ['hey', 'hello', '', 'hello,world', 'hey,world'] >>> list(parse_fields('hey,hello,,"hello,world",\'hey,world\',')) ['hey', 'hello', '', 'hello,world', 'hey,world', ''] >>
  • 是否可以在 awk 中处理包含换行符的字段?(Is it possible to handle fields containing line breaks in awk?)
    问题 假设我有一个包含以下形式记录的文本文件,其中FS通常表示逗号,而RS通常表示换行符。 但是,此规则的一个例外是,如果字段包含在引号中,则应将换行符和逗号视为该字段的一部分。 "This field contains line breaks and is quoted but it should be treated as a single field",1,2,3,"another field" 我如何使用 awk 正确解析这样的文件,在那里我仍然可以像往常一样访问$1,$2... ,但使用上述字段解释? 我已经看过这个 wiki 页面,但是那里提出的解决方案并没有解决换行的问题。 回答1 一个可能但不完美的解决方案是: awk 'BEGIN{RS="\""}{...}' 。通过这样做,您将记录分隔符重置为" ,而字段分隔符仍然是一个空格。 问题是这会在您的文件中添加两个空记录,因为第一个和最后一个"将被匹配为分隔某些记录。 例子: awk 'BEGIN{RS="\""} {print $0,"END OF RECORD",$1,"-",$2}' 应用于您的数据时将产生此结果 END OF RECORD - This field contains line breaks and is quoted but it should be treated as a single
  • 如何从文本文件中写入和读取(包括空格)(How to write and read (including spaces) from text file)
    问题 我正在使用fscanf和fprintf 。 我试图用\t分隔每一行上的字符串并像这样读取它: fscanf(fp,"%d\t%s\t%s",&t->num,&t->string1,&t->string2); 文件内容: 1[TAB]string1[TAB]some string[NEWLINE] 它没有正确读取。 如果我printf("%d %s %s",t->num,t->string1,t->string2)我得到: 1 string1 some 我也收到这个编译警告: warning: format specifies type 'char *' but the argument has type 'char (*)[15]' [-Wformat] 如何在不使用二进制 r/w 的情况下解决此问题? 回答1 我猜"some string"的空格是问题所在。 fscanf()使用%s读取字符串在第一个空白字符处停止。 要包含空格,请使用以下内容: fscanf(fp, "%d\t%[^\n\t]\t%[^\n\t]", &t->num, &t->string1, &t->string2); 另请参阅 fscanf() 和/或另一个 StackOverflow 线程的参考页面,了解在 C 中读取制表符分隔的项目。 [编辑以响应您的编辑:您传递给fscanf(
  • 正则表达式拆分CSV(Regex to split a CSV)
    问题 我知道这个问题(或类似问题)已经被问过很多次了,但是尝试了无数种可能性之后,我一直无法找到一个能100%工作的正则表达式。 我有一个CSV文件,正在尝试将其拆分为一个数组,但是遇到两个问题:用引号引起来的逗号和空元素。 CSV看起来像: 123,2.99,AMO024,Title,"Description, more info",,123987564 我尝试使用的正则表达式是: thisLine.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/) 唯一的问题是,在我的输出数组中,第5个元素显示为123987564,而不是空字符串。 回答1 描述 我认为与其简单地执行匹配并处理所有找到的匹配,不如使用拆分。 该表达式将: 用逗号分隔您的示例文本将处理空值如果不嵌套双引号,将忽略双引号逗号从返回值中修剪定界逗号从返回值中修剪周围的报价 正则表达式: (?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$) 例子 示范文本 123,2.99,AMO024,Title,"Description, more info",,123987564 使用非Java表达式的ASP示例 Set regEx = New RegExp regEx.Global = True regEx.IgnoreCase =
  • 如何提取CSV文件的一列(How to extract one column of a csv file)
    问题 如果我有一个csv文件,是否有一种快速的bash方法可以只打印出任何一列的内容? 可以安全地假设每一行具有相同的列数,但是每一列的内容将具有不同的长度。 回答1 您可以为此使用awk。 将“ $ 2”更改为所需的第n列。 awk -F "\"*,\"*" '{print $2}' textfile.csv 回答2 是的。 cat mycsv.csv | cut -d ',' -f3 cat mycsv.csv | cut -d ',' -f3将打印第三列。 回答3 我能够完成此操作的最简单方法是仅使用csvtool。 我还有其他使用csvtool的用例,如果它们出现在列数据本身中,它可以适当地处理引号或定界符。 csvtool format '%(2)\n' input.csv 用列号替换2将有效地提取您要查找的列数据。 回答4 登陆此处以寻求从制表符分隔的文件中提取信息。 以为我会补充。 cat textfile.tsv | cut -f2 -s 其中-f2提取2,非零索引列或第二列。 回答5 这个问题的许多答案都很棒,有些甚至已经探究了极端情况。 我想添加一个简单的答案,该答案可以每天使用...在这里,您大多会遇到那些极端的情况(例如,用逗号或引号引起来的逗号等)。 FS(字段分隔符)是变量,其值默认为空格。 因此,默认情况下,awk会在空格处拆分任何行。 因此
  • 在 C 中拆分字符串以识别连续的制表符(Split String in C to recognize consecutive tabs)
    问题 我有一个文件,其中某些字段由制表符分隔。 总会有 17 个标签,但顺序可能会有所不同,例如.. 75104\tDallas\t85\t34.46\t45.64 75205\tHouston\t\t37.34\t87.32 93434\t\t\t1.23\t3.32 当我以下列方式使用strtok时 while (fgets(buf, sizeof(buf), fp) != NULL) { tok = strtok(buf,"\t"); while(tok != NULL) { printf("%s->",tok); tok = strtok(NULL,"\t"); } } 我得到了所有的标记,但双标签\t\t或更多被忽略。 但是,我需要知道字段何时为空,我不能让strtok忽略多个选项卡,因为该结构取决于计算的 17 个选项卡,如果字段为空,则使用占位符。 我试过用一个 if(tok == NULL || '') 但我不认为strtok在一个选项卡之后识别一个选项卡。 处理这个问题的最佳方法是什么? 回答1 你不能在你的情况下使用 strtok 。 来自man strtok: strtok() 函数将字符串分解为零个或多个非空标记的序列……从上面的描述可以得出,解析字符串中的两个或多个连续定界符字节的序列被认为是单个定界符,并且字符串开头或结尾的分隔符字节将被忽略。 换句话说
  • 如何在Bash脚本中解析CSV?(How to parse a CSV in a Bash script?)
    问题 我正在尝试解析包含潜在100k +行的CSV。 这是我的标准: 标识符索引标识符值 我想在CSV中检索在给定索引(以逗号分隔)中具有给定值的所有行。 有什么想法需要特别考虑表现吗? 回答1 第一个使用普通旧grep并cut原型: grep "${VALUE}" inputfile.csv | cut -d, -f"${INDEX}" 如果那足够快并且给出正确的输出,那么您就完成了。 回答2 作为基于cut或awk的单线的替代方法,您可以使用专用的csvtool aka ocaml-csv : $ csvtool -t ',' col "$index" - < csvfile | grep "$value" 根据文档,它可以处理转义,引用等。 回答3 观看此youtube视频:BASH脚本第10课,使用CSV文件 CSV档案: Bob Brown;Manager;16581;Main Sally Seaforth;Director;4678;HOME Bash脚本: #!/bin/bash OLDIFS=$IFS IFS=";" while read user job uid location do echo -e "$user \ ======================\n\ Role :\t $job\n\ ID :\t $uid\n\ SITE :\t
  • awk 可以处理在引用字段中包含逗号的 CSV 文件吗?(Can awk deal with CSV file that contains comma inside a quoted field?)
    问题 我正在使用 awk 来计算 csv 文件中一列的总和。 数据格式类似于: id, name, value 1, foo, 17 2, bar, 76 3, "I am the, question", 99 我正在使用这个 awk 脚本来计算总和: awk -F, '{sum+=$3} END {print sum}' name 字段中的某些值包含逗号,这会破坏我的 awk 脚本。 我的问题是:awk 能解决这个问题吗? 如果是,我该怎么做? 谢谢你。 回答1 您在 awk 中编写一个函数,如下所示: $ awk 'func isnum(x){return(x==x+0)}BEGIN{print isnum("hello"),isnum("-42")}' 0 1 你可以在你的脚本中加入这个函数并检查第三个字段是否是数字。如果不是数字,则转到第 4 个字段,如果第 4 个字段不是数字,则转到第 5 个......直到你达到一个数字值。可能一个循环会在这里有所帮助,并将其添加到总和中。 回答2 一种使用GNU awk和 FPAT 的方法 awk 'BEGIN { FPAT = "([^, ]+)|(\"[^\"]+\")" } { sum+=$3 } END { print sum }' file.txt 结果: 192 回答3 您最好使用 Text::CSV 在 perl
  • 如何通过匹配要删除的变量文本前后的两个已知模式来删除行/字符串中间的一部分(How to remove part of the middle of a line/string by matching two known patterns in front and behind variable text to be removed)
    问题 如何通过匹配两个已知模式来删除行/字符串中间的一部分,一个在要删除的文本前面,另一个在要删除的文本后面? 我有一个包含数千行、逗号分隔记录的 Linux 文本文件。 不幸的是,所有记录的格式都不相同。 每行可能有多达四个逗号分隔的字段,其中只有第一个和最后一个是常量,中间的两个字段可能存在,也可能不存在。 现有行(记录)格式的示例。 杂乱的数据,但第一个字段始终存在,最后一个字段也是如此,以单词 ADDED 开头。 FNAME LNAME, SOME COMMENT, JOINED DATE, ADDED TO DB DATE FNAME LNAME, ADDED TO DB DATE FNAME LNAME, SOME COMMENT, ADDED TO DB DATE FNAME LNAME, JOINED DATE, ADDED TO DB DATE 目标是保留包括逗号在内的第一个字段,丢弃第一个逗号之后的所有内容,保留单词“ADDED”以及行尾后面的所有内容,并在第一个逗号和单词 ADDED 之间插入一个空格。 对于解析文件中的每一行,从行首到第一个逗号(保留这个)。 将行的其余部分解析到“已添加”一词之前的空格并将其丢弃。 保留从单词“ADDED”之前的空格到行尾的所有内容,并将第一部分和最后一部分连接起来以形成每行一条记录,其中两个字段由逗号和空格分隔。