我有一个逗号分隔的字符串,它可能包含空字段。 例如:
1,2,,4
使用基本
sscanf(string,"%[^,],%[^,],%[^,],%[^,],%[^,]", &val1, &val2, &val3, &val4);
我得到的所有之前的空字段的值,然后从起空场意外的结果。
当我从sscanf的删除表达式的空字段(),
sscanf(string,"%[^,],%[^,],,%[^,],%[^,]", &val1, &val2, &val3, &val4);
一切顺利的罚款。
因为我不知道什么时候我会得到一个空场呢,有没有办法改写表达很好地处理空字段?
Answer 1:
如果您使用strtok
用逗号作为分隔符,你会得到字符串的一个或多个,其中的列表将是空的/零长度。
看看我的答案在这里了解更多信息。
Answer 2:
男人的sscanf :
[
与从指定接受字符集中的字符的一个非空序列;
(强调)。
Answer 3:
这就像你正在处理的CSV值。 如果您需要扩展它来处理引用的字符串(这样的字段可以包含逗号,例如),你会发现scanf
-家庭无法处理的格式的所有复杂。 因此,你需要使用专门用来处理代码(您的变体)CSV格式。
你会发现在“一组CSV库实现的讨论编程实践 ” -在C和C ++。 毫无疑问,有许多其他问题。
Answer 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
Answer 5:
把一个“*”的“%”之后跳过阅读。 此外,可以仅读取3个字符指出“%3S”例如。
Answer 6:
我来到这里寻找答案,以同样的问题。 我不想scanf函数funcion留下任何。 最后,我建立一个zsscanf我自己,我在那里解析的格式,sscanf'ed一个每一个数据,并检查的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
, %...[...]
需要分离为%...[...]
否则我真的哈德关心格式字符串,这样我只在乎%
)。
Answer 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
Answer 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
Answer 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格式读给一个float数组 :
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
Answer 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()
文章来源: How do I parse out the fields in a comma separated string using sscanf while supporting empty fields?