Stdin + 字典文本替换工具 -- 调试

Stdin + Dictionary Text Replacement Tool -- Debugging

我正在处理一个项目,其中有两个主要文件。本质上,该程序读取一个文本文件,该文件定义了一个具有键值映射的字典。每个键都有一个唯一的值,文件格式如下,其中每个键值对都在其自己的行上:

ipsum i%#@!
fubar fubar
IpSum XXXXX24
Ipsum YYYYY211

然后程序从 stdin 读取输入,如果任何“单词”与字典文件中的键匹配,它们将被替换为值。大写和小写有点不同——这是“匹配优先级”的顺序

  1. 确切的单词在替换集中
  2. 除了第一个字符以外的所有字符都转换为小写的单词在替换集中
  3. 完全转换为小写的单词在替换集中

意思是如果字典中有确切的词,它就会被替换,但如果没有,则检查下一个可能性 (2),依此类推...

我的程序通过了我们提供的基本案例,但随后终端显示 输出与参考二进制文件不同。

我进入了两个文件(不是 c 文件,而是二进制文件),一个超长,有很多数字,另一个只有一行随机字符。所以这并没有真正的帮助。我还检查了我的代码并进行了一些小测试,但似乎没问题?一位朋友建议我确保我正在考虑 processInput() 中的 null 运算符,而我已经这样做了(或者至少我是这么认为的,如果我错了请纠正我)。我还将 getchar() 转换为 int 以正确检查 EOF,并为 char 数组分配了额外的 space。我也尝试了 vimdiff 并且变得更加困惑。请帮我调试一下!我弄了一整天,我很困惑。

首先使用以下方法测试您的分词器:

$ ./a.out <badhash2.c >zooi
$ diff badhash2.c zooi
$

它也适用于二进制文件吗?:

$ ./a.out <./a.out > zooibin
$ diff ./a.out zooibin
$

是的,确实如此!


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

void processInput(void);

int main(int argc, char **argv) {
  processInput();
  return 0;
}

void processInput() {
  int ch;
  char *word;
  int len = 0;
  int cap = 60;
  word = malloc(cap);

  while(1) {
    ch = getchar();                 // (1)
    if( ch != EOF && isalnum(ch)) { // (2)
        if(len+1 >= cap) {          // (3)
            cap += cap/2;
            word = realloc(word, cap);
        }
        word[len++] = ch;
    } else {
        if (len) {                  // (4)
#if 0
            char key[len + 1]; 
            memcpy(key, word, len); key[len] = 0; 
            checkData(key, len); 
#else
            word[len] = 0;
            fputs(word, stdout); 
#endif
            len = 0; 
            }
        if (ch == EOF) break;      // (5)
        putchar(ch); 
      }
    }
    free(word);

  }
                         

我只修复了你的分词器,遗漏了哈希 table 和搜索与替换的东西。现在应该生成输入的逐字副本。 (这很愚蠢,但非常适合测试)

  1. 如果要允许二进制输入,则不能使用 while((ch = getchar()) ...) :输入中的 NUL 会导致循环结束。您必须推迟对 EOF 的测试,因为它们可能仍然是您缓冲区中的最终决定 ...&& ch != EOF)

  2. 在这里把 EOF 当作 space 对待:它可以是一个词的结尾

  3. 你也必须为 NUL ('\0') 保留 space。

  4. if (len==0) 就没有字了,不用查了

  5. 我们像对待 space 一样对待 EOF,但我们不想将其写入输出。是时候打破循环了。

processInput() 函数中存在多个问题:

  • 当字节读取为 0 时循环不应停止,您应该使用以下方法处理完整输入:

      while ((ch = getchar()) != EOF)
    
  • EOF 的测试实际上应该以不同的方式进行,因此如果文件的最后一个单词恰好出现在文件末尾,则它有机会被处理。

  • isalnum((char)ch) 中的转换不正确:您应该将 ch 直接传递给 isalnum。强制转换为 char 实际上会适得其反,因为它将超出 CHAR_MAX 的字节值转换为负值,而 isalnum() 具有未定义的行为。

  • 测试if(ind >= cap)过于宽松:如果word包含cap个字符,在word[ind]处设置空终止符将超出结尾的阵列。将测试更改为 if (cap - ind < 2) 以始终允许一个字节和一个空终止符。

  • 你应该检查单词中至少有一个字符,以避免用空字符串调用 checkData()

  • char key[ind + 1]; 没用:您可以将 word 传递给 checkData().

  • checkData(key, ind) 不正确:您应该为大小写转换传递缓冲区的大小,它至少 ind + 1 以允许空终止符。

  • putchar((char)ch); 中的演员表无用且令人困惑。

其余代码中存在一些小问题,但none应该会导致问题。