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

标签 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 字符中* 多变的。我尝试了其他帖子中提出的多种解决方案,例如指定排除某些字符的格式,但没有任何效果。

如果有任何提示可以解决问题,我将不胜感激!

最佳答案

根据您的评论,如果您要在现有的评论 之后添加另一个数字,这会使事情变得有点复杂。原因是对于包含多个单词的 comment,您没有要搜索的离散端。

但是,C 很少让您失望。每当您需要从一行或缓冲区解析数据时,您都会查看数据的格式并问“我将使用什么作为我需要的开始或结束的引用?”在这里,没有任何注释,我们需要使用缓冲区的末尾作为引用并向后工作。

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

为了解决这个问题,我们将解析行分成两部分。我们可以以可靠的方式使用我们最初的 sscanf 调用读取评论之前的所有内容。因此,我们将考虑第 1 部分一行的第一部分(直到并包括 float )中的所有内容,以及第 2 部分注释字符 // 之后的所有内容。您像往常一样阅读/解析第 1 部分:

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

在一行中搜索一个特定的字符,我们有一个手动的逐个字符的比较(我们总是这样做)并且我们有 strchrstrrchr 函数string.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

注意:处理此问题的不同方法没有限制。这只是一种方法。另一种方法是将整行标记成单独的单词,检查每个单词是否以数字开头(并包含一个“.”表示 float ),然后简单地转换所有数字并连接所有非数字根据需要的话。由你决定。您的工具箱越大,您会发现处理它的方法就越多。

关于c - 使用 sscanf 从字符串中读取多个单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30419025/

相关文章:

c - Linux套接字绑定(bind)连接

C - 根据值移动或删除多个节点

python - 如何使用python生成多个文件路径并将它们保存到excel中

c - 循环扫描直到回车

c++ - 格式说明符 C++ 有什么问题

c - 返回一个包含从 a 到 b 的所有整数的数组

c - 我程序中的段错误

java - 如何将对象数组合并为单个格式化字符串

php - php中如何删除字符串的一部分

c - 与 sscanf 一起使用的格式说明符 %n 不返回字符数