【问题标题】:Stdin + Dictionary Text Replacement Tool -- Debugging标准输入+字典文本替换工具——调试
【发布时间】:2021-05-10 23:46:30
【问题描述】:

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

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

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

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

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

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

我查看了这两个文件(不是 c 文件,而是二进制文件),一个非常长,包含大量数字,另一个只有一行随机字符。所以这并没有真正帮助。我还查看了我的代码并进行了一些小测试,但看起来还可以吗?一位朋友建议我确保我在 processInput() 中考虑了 null 运算符并且我已经是(或者至少我认为是这样,如果我错了,请纠正我)。我还将 getchar() 转换为 int 以正确检查 EOF,并为 char 数组分配了额外的空间。我也试过vimdiff 并且更加困惑。我希望得到一些帮助来调试这个,拜托!我整天都在做这件事,我很困惑。

【问题讨论】:

  • 对不起!我不知道这是必需的。最初我担心如果我把它全部放在那里会很长而且很混乱。无论如何,它现在起来了!谢谢你告诉我
  • 你有函数。你可以测试它们。
  • stringEquals 函数存在问题(但不是您要查找的问题)。相等的哈希值与相等的字符串不同。例如,字符串"Bb""CA" 具有相同的哈希值。我认为您应该将void 指针转换为char 指针,然后使用strcmp 检查字符串是否相等。
  • @user3386109 谢谢!我修好了。任何想法我正在寻找的问题是什么?
  • @wildplasser 我正在尝试

标签: c string dictionary binary stdin


【解决方案1】:

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); 中的演员阵容毫无用处且令人困惑。

其余代码中存在一些小问题,但都不会导致问题。

【讨论】:

  • 哦,我相信第一个建议解决了它!非常感谢!我有几个后续问题——你会建议我如何处理输入文件不在新行结束的边缘情况?我正在运行一个包含两行文本的测试(第 1 行的 lorem,第 2 行的 IPSUM,最后没有新行),但我的程序只输出一行(lorem,不在字典中)。我尝试添加另一个 if 语句来检查是否 ch=='\n' 然后输出它,但我仍然有问题
  • 另外,您通常如何知道要加 1(例如 checkData)?如果数组从零索引开始, ind 应该不够吗?
  • @Manaal:我修复了processInput() 的代码,以处理文件末尾单词的边缘情况。对EOF 的测试在处理该单词后进行(如果有)。如果有人想知道,isalnum(EOF) 被指定为返回 0。
  • @Manaal:函数checkData 中的本地数组copy 的大小必须为strlen(key) + 1,因为空终止符。更改大小写不会更改字符串长度(对于 UTF-8 编码的字符串不会如此,但这里您只处理单字节字符集)。
  • 再次感谢!顺便说一句,我删除了原始帖子中的代码,以防止我班上的其他学生看到它。如果你也能删减你的答案/代码,我真的很感激! :))
【解决方案2】:

首先测试您的标记器:

$ ./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);

  }
                         

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

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

  2. 在这里将 EOF 视为一个空格:它可能是一个单词的结尾

  3. 您也必须为 NUL ('\0') 保留空间。

  4. 如果 (len==0) 就没有单词,所以不需要查找。

  5. 我们将 EOF 视为一个空格,但我们不想将其写入输出。是时候跳出循环了。

【讨论】:

  • 在测试标记器时,我将如何输入四个参数——输入(比如它的 input.txt)、字典(dict.txt)、参考输出(corrOut.txt)和实际输出(output.txt)?
  • 另外,当我在你推荐的 if(ind) 中添加时,两个测试都失败了:(
  • 还有几个问题——为什么我们需要给 if 语句加上标签,为什么第一个 if 是 0? isnt 0 总是假的,这意味着该部分不会执行?
  • 我也很困惑为什么我们将 while (ch!= EOF) 条件移动到 if 语句中,如果我们有一个 if 语句在最后检查相同的内容并在需要时中断?
  • hashtag if statements(你的意思是:#if 0 )是一种有条件地注释掉代码的方法。
猜你喜欢
  • 1970-01-01
  • 2023-03-28
  • 2022-10-24
  • 1970-01-01
  • 2012-07-25
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 1970-01-01
相关资源
最近更新 更多