【问题标题】:fscanf() how to go in the next line?fscanf() 如何进入下一行?
【发布时间】:2015-10-21 12:29:00
【问题描述】:

所以我在一个文件中有一个文本墙,我需要识别 $ 符号之间的一些单词并将它们称为数字,然后在另一个文件中打印修改后的文本以及数字对应的内容。 此外,未定义行,列最多应为 80 个字符。

例如:

I $like$ cats.  
I [1] cats.  
[1] --> like

这就是我所做的:

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

    #define N 80
    #define MAX 9999
    int main()
    {
        FILE *fp;
        int i=0,count=0;
        char matr[MAX][N];

        if((fp = fopen("text.txt","r")) == NULL){
            printf("Error.");
            exit(EXIT_FAILURE);
        }

        while((fscanf(fp,"%s",matr[i])) != EOF){
            printf("%s ",matr[i]);
            if(matr[i] == '\0')
                printf("\n");

            //I was thinking maybe to find two $ but Idk how to replace the entire word     
            /*                                 
            if(matr[i] == '$')
                count++;
            if(count == 2){
                ...code...
            }
            */
            i++;
        }



        fclose(fp);
        return 0;
   }

我的问题是 fscanf 无法识别 '\0',因此当我打印数组时它不会进入下一行。我也不知道如何用数字替换 $word$

【问题讨论】:

  • fscanf("%s") 只会读一个字。如果要处理行,请使用fgets()

标签: c text scanf words


【解决方案1】:

fscanf("%s") 不仅会一次读取一个以空格分隔的字符串,还会吃掉这些字符串之间的所有空格,包括行终止符。如果您想在输出中重现输入空格,正如您的示例所建议的那样,那么您需要一种不同的方法。

还没有定义行,列最多应为 80 个字符。

我认为这意味着 行数 是事先不知道的,并且可以假设没有一行包含超过 80 个字符(不包括任何行终止符)。

当你说

我的问题是 fscanf 无法识别 '\0' 所以当我打印数组时它不会进入下一行

我想你说的是这段代码:

        char matr[MAX][N];
            /* ... */
            if(matr[i] == '\0')

鉴于matr 的声明,给定条件将始终评估为false,而不管任何其他考虑。 fscanf() 根本不考虑。 matr[i] 的类型是 char[N]N 类型为 char 的元素的数组。计算结果为指向数组第一个元素的指针,该指针永远不会是NULL。看起来您正在尝试确定何时编写换行符,但没有任何类似这种方法可以做到这一点。

我建议您首先按照@Barmar 的建议通过fgets() 逐行阅读。可能看起来像这样:

char line[N+2]; /* N + 2 leaves space for both newline and string terminator */

if (fgets(line, sizeof(line), fp) != NULL) {
    /* one line read; handle it ... */
} else {
    /* handle end-of-file or I/O error */
}

然后,对于您阅读的每一行,以您喜欢的任何方式解析出"$word$" 标记,并输出所需的结果(除了$ 分隔标记之外的所有内容;每个标记的括号替换号)。当然,您需要记住替换标记以供以后输出。请记住制作这些文件的副本,因为缓冲区将在每次读取时被覆盖(如果按照我上面的建议完成)。

【讨论】:

  • 我知道fgets() 有效,问题是我避免使用它,因为它读取了所有行,所以我不知道如何只更改 $ 符号之间的单词。我想逐字阅读,然后如果找到两个 $ 符号,我会用数字切换单词。
  • 事实仍然是scanf() 不会轻易做你想做的事。大家给你的建议是,读完后用string-manipulation函数甚至普通算术运算来分析每一行,从而挑出$-delimited的单词。
  • 尽管如此,如果您坚持使用 fscanf() 进行解析,那么您将需要依赖不跳过空格的字段描述符:%[%c。这样的方法会很棘手而且有点晦涩,但可能。
【解决方案2】:

fscanf()确实在特定情况下识别“\0”,但这不是这里的问题。

代码需要检测'\n'fscanf(fp,"%s"... 不会那样做。 "%s" 指示的第一件事是消耗(而不是保存)任何前导空白,包括 '\n'。用fgets()阅读一行文字。

一次简单读取 1 行。然后沿着缓冲区前进,寻找单词。
以下使用"%n" 跟踪缓冲区扫描停止的距离。

// more room for \n \0
#define BUF_SIZE (N + 1 + 1) 
char buffer[BUF_SIZE];

while (fgets(buffer, sizeof buffer, stdin) != NULL) {
  char *p = buffer;
  char word[sizeof buffer];
  int n;
  while (sscanf(p, "%s%n", word, &n) == 1) {
    // do something with word
    if (strcmp(word, "$zero$") == 0) fputs("0", stdout);
    else if (strcmp(word, "$one$") == 0) fputs("1", stdout);
    else fputs(word, stdout);
    fputc(' ', stdout);
    p += n;
  }
  fputc('\n', stdout);
}

【讨论】:

    【解决方案3】:

    使用 fread() 将文件内容读取到 char[] 缓冲区。然后遍历这个缓冲区,每当你找到一个 $ 时,你都会执行一个 strncmp 来检测用哪个值替换它(请记住,单词末尾有第二个 $ )。要将 $word$ 替换为数字,您需要在单词的位置缩小或扩展缓冲区 - 这取决于 ascii 格式的数字的字符串大小(在 google 上查找解决方案,通常您应该能够使用记忆移动)。然后您可以将数字写入洞穴,这是由于扩展缓冲区而产生的(也只需覆盖 $word$)。 然后将缓冲区写入文件,覆盖之前的所有内容。

    【讨论】:

      猜你喜欢
      • 2021-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多