使用sscanf从字符串中读取多个单词

时间:2015-05-24 00:48:19

标签: c string scanf

我正在尝试从文件中读取格式化内容。为此,我使用fgets()sscanf()逐行阅读。

文件的内容应该是一个表。一行看起来像下面的例子:

456    2    39    chained_words    62.5    // comment with more than one word

要阅读它,我使用:

fgets(temp,MAXLINELENGTH,file);
sscanf(temp,"%d %d %d %s %f // %s",&num1,&num2,&num3,word,&num4,comment);

前五个元素加上//之后的第一个单词可以正常工作,但问题是我需要将整个注释存储在comment char *变量中。我尝试过在其他帖子中提出的多种解决方案,比如指定排除某些字符的格式,但没有任何效果。

我很感激任何解决问题的暗示!

1 个答案:

答案 0 :(得分:3)

根据您的评论,如果您要在现有comment之后添加另一个号码,那会使事情变得复杂一些。原因是如果comment包含多个单词,则您没有离散的搜索结尾。

然而,C很少让你失望。每当您需要解析行或缓冲区中的数据时,您会查看数据的格式并询问“我将使用什么作为我需要的开头或结尾的参考?”在这里,评论中没有任何内容,我们需要使用缓冲区的末尾作为参考并向后工作。

这样做我们将假设该值是换行符之前的行上的最后一个内容(后面没有制表符或空格)。我们可以向后循环,直到我们找到要验证的最后一个非空白字符,但为了达到目的,我们做出了假设。

出于这个问题的目的,我们将解析线分为两部分。我们可以通过原始sscanf电话以可靠的方式阅读评论中的所有内容。因此,我们将考虑一行中第一部分(包括浮点数)第1部分的所有内容,以及注释字符//第2部分之后的所有内容。您可以像往常一样阅读/解析第一部分:

        sscanf (line, "%d %d %d %s %f", &d1, &d2, &d3, word, &f1);

在一行中搜索特定字符时,我们进行了逐个字符比较(我们总是这样做),strchr中有strrchrstring.h个函数将搜索给定字符的第一个(strchr)或最后一个(strrchr)出现的文本行。两个函数都在字符串中返回指向该字符的指针

从我们行的末尾向后工作,如果我们找到/,我们现在在注释开始之前有一个指针(字符串中的地址)到最后'/'。我们现在使用指针将行的其余部分读入comment(值和全部)。

        p = strrchr (line, '/');            /* find last '/' in line    */
        sscanf (p, "/ %[^\n]%*c", comment); /* read comment and value   */

现在我们只使用comment(而不是line)。我们知道,如果我们从comment的末尾开始寻找空格' ',我们将能够读取我们的最后一个值。在我们读取最后一个值之后,因为我们的指针指向值之前的地址,我们知道我们可以在指针处null-terminate comment完成我们的解析。

        p = strrchr (comment, ' ');         /* find last space in file  */
        sscanf (p, " %d", &d4);             /* read last value into d4  */
        *p = 0;                             /* null-terminate comment   */

注意:如果需要,您可以检查/删除comment中的任何尾随空格,但出于我们的目的,这是省略的)

总而言之,你会看到这样的东西:

快速示例

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

#define MAXS 128

int main (int argc, char **argv) {

    if (argc < 2 ) {                /* check for at least 1 argument    */
        fprintf (stderr, "error: insufficient input, usage: %s filename\n", 
                argv[0]);
        return 1;
    }

    char line[MAXS] = {0};
    char word[MAXS] = {0};
    char comment[MAXS] = {0};
    char *p = NULL;
    size_t idx = 0;
    int d1, d2, d3, d4;
    float f1 = 0.0;
    FILE *fp = NULL;

    d1 = d2 = d3 = d4 = 0;

    if (!(fp = fopen (argv[1], "r"))) {  /* open/validate file   */
        fprintf (stderr, "error: file open failed '%s'.", argv[1]);
        return 1;
    }

    while (fgets (line, MAXS, fp) != NULL)  /* read each line in file */
    {
        /* read buffer through first float */
        sscanf (line, "%d %d %d %s %f", &d1, &d2, &d3, word, &f1);

        p = strrchr (line, '/');            /* find last '/' in line    */
        sscanf (p, "/ %[^\n]%*c", comment); /* read comment and value   */
        p = strrchr (comment, ' ');         /* find last space in file  */
        sscanf (p, " %d", &d4);             /* read last value into d4  */
        *p = 0;                             /* null-terminate comment   */

        printf ("\nline : %zu\n\n %s\n", idx, line);
        printf ("   d1 : %d\n   d2 : %d\n   d3 : %d\n   d4 : %d\n   f1 : %.2f\n",
                d1, d2, d3, d4, f1);
        printf ("   chained : %s\n   comment : %s\n", word, comment);

        idx++;
    }

    fclose (fp);

    return 0;
}

<强>输入

$ cat dat/strwcmt.txt
456    2    39    chained_words    62.5    // comment with more than one word    227
457    2    42    more_chained_w   64.5    // another comment    228
458 3 45 s_n_a_f_u 66.5 // this is still another comment 229

<强>输出

$ ./bin/str_rd_mixed dat/strwcmt.txt

$ ./bin/str_rd_mixed dat/strwcmt.txt

line : 0

 456    2    39    chained_words    62.5    // comment with more than one word    227

   d1 : 456
   d2 : 2
   d3 : 39
   d4 : 227
   f1 : 62.50
   chained : chained_words
   comment : comment with more than one word

line : 1

 457    2    42    more_chained_w   64.5    // another comment    228

   d1 : 457
   d2 : 2
   d3 : 42
   d4 : 228
   f1 : 64.50
   chained : more_chained_w
   comment : another comment

line : 2

 458 3 45 s_n_a_f_u 66.5 // this is still another comment 229

   d1 : 458
   d2 : 3
   d3 : 45
   d4 : 229
   f1 : 66.50
   chained : s_n_a_f_u
   comment : this is still another comment

注意:处理此问题的方法不限。这只是一种方法。另一种方法是将标记化整行作为单独的单词,检查每个单词是否以数字开头(并且包含浮点数'。')然后只需转换所有数字并连接所有非数字根据需要的话。由你决定。您的工具箱越大,您看到它的方式就越多。