使用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 或函数对 strcspnstrspn.

例如

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

程序输出同上图

这是一个使用标准函数 strcspnstrspn 的演示程序。

#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,然后将复制的字符附加到终止零。