使用sscanf解析单行的一长行单词
Using sscanf to parse a long line of words on a single line
在开发一个小程序来扫描关键数据项的英文单词行时,我选择了 sscanf() 来解析该行。由于每行中存在未知数量的单词,因此必须使用请求中指定的最大可能字段数调用 sscanf()。这导致了一个又长又难看的单行语句。一种更简洁的技术是使用 sscanf() 在编程循环中一次获取一个单词。不幸的是,不可能知道 sscanf() 跳过了多少个空格来获取下一个字段。因此,不可能使用反映 sscanf() 在上一次调用中停止的确切位置的字符串指针再次调用 sscanf()。代码示例如下。两个问题:1) 我在 sscanf() 的使用中遗漏了什么吗?和 2) 在 c 中有更好的方法吗?
#include <stdio.h>
#include <string.h>
/*
* using sscanf to parse a line (null terminated string) with fields (words)
* separated by one or more spaces into an array of words (fields).
*/
void main()
{
int i,j;
int idx;
char string[100] = "word1 word2 word3 word4 word5 word6 word7[=10=]";
char fields[20][10];
#if 1
j=sscanf (&string[0], "%s%s%s%s%s%s", &fields[0][0], &fields[1][0], &fields[2][0], &fields[3][0], &fields[4][0], &fields[5][0]);
printf("sscanf returned: %d\n",j);
#else
/*
* this would be the preferred way to parse a long line of words,
* but there is no way to know with certainty how many spaces sscanf
* skipped over to obtain the next string (word). A modified version
* of sscanf that either modified an integer pointer argument or
* updated the pointer to the input string (line) would allow
* subsequent calls to pick up where the last sscanf call left off.
*
*/
for (i=0,idx=0;i<6;i++){
j=sscanf (&string[idx], "%s", &fields[i][0]);
idx += strlen(&fields[i][0]);
printf("sscanf returned: %d\n",j);
if (j==0)
break;
}
#endif
for (i=0;i<6;i++){
printf("%s",&fields[i][0]);
}
printf("\n");
return;
}
在用作初始值设定项的字符串文字中
char string[100] = "word1 word2 word3 word4 word5 word6 word7[=10=]";
明确的终止零是多余的。除了明确的终止零之外,字符串文字已经包含终止零。
给你。
#include <stdio.h>
int main(void)
{
char string[100] = "word1 word2 word3 word4 word5 word6 word7";
char s[10];
const char *p = string;
for ( int n = 0; sscanf( p, "%s%n", s, &n ) == 1; p += n )
{
puts( s );
}
return 0;
}
程序输出为
word1
word2
word3
word4
word5
word6
word7
另一种方法是使用标准函数 strtok
或函数对 strcspn
和 strspn
.
例如
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[100] = "word1 word2 word3 word4 word5 word6 word7";
const char *delim = " \t";
const char *p = strtok( string, delim );
while ( p != NULL )
{
puts( p );
p = strtok( NULL, delim );
}
return 0;
}
程序输出同上图
这是一个使用标准函数 strcspn
和 strspn
的演示程序。
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[100] = "word1 word2 word3 word4 word5 word6 word7";
const char *delim = " \t";
for ( const char *p = string; *p; )
{
p += strspn( p, delim );
const char *q = p;
p += strcspn( p, delim );
int n = p - q;
if ( n ) printf( "%*.*s\n", n, n, q );
}
return 0;
}
再次输出与上面显示的相同。
注意,在这种情况下,提取的单词不是零终止的。因此,要将它们作为字符串复制到字符数组中,您应该使用 memcpy
,然后将复制的字符附加到终止零。
在开发一个小程序来扫描关键数据项的英文单词行时,我选择了 sscanf() 来解析该行。由于每行中存在未知数量的单词,因此必须使用请求中指定的最大可能字段数调用 sscanf()。这导致了一个又长又难看的单行语句。一种更简洁的技术是使用 sscanf() 在编程循环中一次获取一个单词。不幸的是,不可能知道 sscanf() 跳过了多少个空格来获取下一个字段。因此,不可能使用反映 sscanf() 在上一次调用中停止的确切位置的字符串指针再次调用 sscanf()。代码示例如下。两个问题:1) 我在 sscanf() 的使用中遗漏了什么吗?和 2) 在 c 中有更好的方法吗?
#include <stdio.h>
#include <string.h>
/*
* using sscanf to parse a line (null terminated string) with fields (words)
* separated by one or more spaces into an array of words (fields).
*/
void main()
{
int i,j;
int idx;
char string[100] = "word1 word2 word3 word4 word5 word6 word7[=10=]";
char fields[20][10];
#if 1
j=sscanf (&string[0], "%s%s%s%s%s%s", &fields[0][0], &fields[1][0], &fields[2][0], &fields[3][0], &fields[4][0], &fields[5][0]);
printf("sscanf returned: %d\n",j);
#else
/*
* this would be the preferred way to parse a long line of words,
* but there is no way to know with certainty how many spaces sscanf
* skipped over to obtain the next string (word). A modified version
* of sscanf that either modified an integer pointer argument or
* updated the pointer to the input string (line) would allow
* subsequent calls to pick up where the last sscanf call left off.
*
*/
for (i=0,idx=0;i<6;i++){
j=sscanf (&string[idx], "%s", &fields[i][0]);
idx += strlen(&fields[i][0]);
printf("sscanf returned: %d\n",j);
if (j==0)
break;
}
#endif
for (i=0;i<6;i++){
printf("%s",&fields[i][0]);
}
printf("\n");
return;
}
在用作初始值设定项的字符串文字中
char string[100] = "word1 word2 word3 word4 word5 word6 word7[=10=]";
明确的终止零是多余的。除了明确的终止零之外,字符串文字已经包含终止零。
给你。
#include <stdio.h>
int main(void)
{
char string[100] = "word1 word2 word3 word4 word5 word6 word7";
char s[10];
const char *p = string;
for ( int n = 0; sscanf( p, "%s%n", s, &n ) == 1; p += n )
{
puts( s );
}
return 0;
}
程序输出为
word1
word2
word3
word4
word5
word6
word7
另一种方法是使用标准函数 strtok
或函数对 strcspn
和 strspn
.
例如
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[100] = "word1 word2 word3 word4 word5 word6 word7";
const char *delim = " \t";
const char *p = strtok( string, delim );
while ( p != NULL )
{
puts( p );
p = strtok( NULL, delim );
}
return 0;
}
程序输出同上图
这是一个使用标准函数 strcspn
和 strspn
的演示程序。
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[100] = "word1 word2 word3 word4 word5 word6 word7";
const char *delim = " \t";
for ( const char *p = string; *p; )
{
p += strspn( p, delim );
const char *q = p;
p += strcspn( p, delim );
int n = p - q;
if ( n ) printf( "%*.*s\n", n, n, q );
}
return 0;
}
再次输出与上面显示的相同。
注意,在这种情况下,提取的单词不是零终止的。因此,要将它们作为字符串复制到字符数组中,您应该使用 memcpy
,然后将复制的字符附加到终止零。