我目前正在尝试使用以下格式解析UnicodeData.txt:ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html但是,当我尝试阅读时,我遇到了一个问题,请说出如下所示的行。
something;123D;;LINE TABULATION;
我尝试通过以下代码从字段中获取数据。问题是字段[3]没有填写,scanf返回2. in
是当前行。
char fields[4][256];
sscanf(in, "%[^;];%[^;];%[^;];%[^;];%[^;];",
fields[0], fields[1], fields[2], fields[3]);
我知道这是scanf()
的正确实现,但是有没有办法让它工作,而不是自己创建scanf()
?
答案 0 :(得分:2)
如果您想考虑以下替代方案,请使用scanf
和"%n"
格式说明符(用于读取到目前为止已读取的字符数)为整数:< / p>
#include <stdio.h>
#define N 4
int main( ){
char * str = "something;123D;;LINE TABULATION;";
char * wanderer = str;
char fields[N][256] = { 0 };
int n;
for ( int i = 0; i < N; i++ ) {
n = 0;
printf( "%d ", sscanf( wanderer, "%255[^;]%n", fields[i], &n ) );
wanderer += n + 1;
}
putchar( 10 );
for ( int i = 0; i < N; i++ )
printf( "%d: %s\n", i, fields[i] );
getchar( );
return 0;
}
在每个循环中,它会将最多255个字符读入相应的fields[i]
,直到遇到分隔符分号;
。读完之后,它会读取它已经阅读了多少个字符,进入n
,之前已经归零(哦,我的......)。
它增加了指向字符串的指针,读取的字符数加上分隔符分号的一个。
printf
表示sscanf
的返回值,打印结果仅用于演示目的。您可以看到代码在http://codepad.org/kae8smPF上工作,而getchar();
和for
声明已移到外面以符合C90标准。
答案 1 :(得分:2)
scanf
无法处理“空”字段。所以你必须自己解析它。
以下解决方案是:
strchr
而非慢sscanf
函数parse
从输入str
中提取以分号分隔的字段。四个分号给出五个区域,其中一些或全部可以是空白的。没有规定逃离分号。
#include <stdio.h>
#include <string.h>
static int parse(char *str, char *out[], int max_num) {
int num = 0;
out[num++] = str;
while (num < max_num && str && (str = strchr(str, ';'))) {
*str = 0; // nul-terminate previous field
out[num++] = ++str; // save start of next field
}
return num;
}
int main(void) {
char test[] = "something;123D;;LINE TABULATION;";
char *field[99];
int num = parse(test, field, 99);
int i;
for (i = 0; i < num; i++)
printf("[%s]", field[i]);
printf("\n");
return 0;
}
该测试程序的输出是:
[something][123D][][LINE TABULATION][]
更新:一个稍短的版本,不需要额外的数组来存储每个子字符串的开头,是:
#include <stdio.h>
#include <string.h>
static int replaceSemicolonsWithNuls(char *p) {
int num = 0;
while ((p = strchr(p, ';'))) {
*p++ = 0;
num++;
}
return num;
}
int main(void) {
char test[] = "something;123D;;LINE TABULATION;";
int num = replaceSemicolonsWithNuls(test);
int i;
char *p = test;
for (i = 0; i < num; i++, p += strlen(p) + 1)
printf("[%s]", p);
printf("\n");
return 0;
}
答案 2 :(得分:1)
我认为sscanf
无法满足您的需求:sscanf
格式%[^;]
将匹配非空 的序列 - 分号字符。另一种方法是使用readline
,分隔符为';'
,如:
#include <iostream>
#include <sstream>
#include <string>
int main() {
using namespace std;
istringstream i { "something;123D;;LINE TABULATION;\nsomething;123D;;LINE TABULATION;\nsomething;123D;;LINE TABULATION;\n" };
string a, b, c, d, newline;
while( getline(i, a, ';') && getline(i, b, ';') && getline(i, c, ';') && getline (i, d, ';') && getline(i, newline) )
cout << d << ',' << c << '-' << b << ':' << a << endl;
}
(我现在只看到你从c++
标记中删除了这个问题,如果你的问题只有c,我还有另一个解决方案,如下:)
#include <string.h>
#include <stdio.h>
int main() {
typedef char buffer[2048];
buffer line;
while( fgets(line, sizeof(line), stdin) > 0 ) {
printf("(%s)\n", line);
char *end = line;
char *s1 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
char *s2 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
char *s3 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
char *s4 = *end == ';' ? (*end = '\0'), end++ : strtok_r(end, ";", &end);
printf("[%s][%s][%s][%s]\n", s4, s3, s2, s1);
}
}