2012-02-13 70 views
7

我正在测试C#的metaphone实现并将其结果与PHP中内置的metaphone()函数进行比较。但是,我遇到了一个错误(它是previously documented in PHP's issue tracker并在a mailing list上讨论过),但我试图了解他们错误背后的C代码,这是为了我个人的兴趣。PHP metaphone实现bug

基本上,根据metaphone算法,大多数-gh-的实例应该呈现为沉默。在“莱特”的具体测试情况下,我希望(和我自己的算法生成)“RT”的变音键

"wr" => R 
"i" => ignored 
"gh" => ignored 
"t" => T 

Result: RT 

然而,PHP的音位函数返回RFT。显然,它将-gh-转换为F,就好像它在一个单词的末尾(例如“粗糙”),但在“wright”这个词的情况下,这是不正确的,因为-gh-确实不是在词的结尾。看着在PHP源代码分发的metaphone.c文件,我看到的一些关键的东西:

/* These prevent GH from becoming F */ 
#define NOGHTOF(c) (ENCODE(c) & 16) /* BDH */ 

... 

/* Go N letters back. */ 
#define Look_Back_Letter(n) (w_idx >= n ? toupper(word[w_idx-n]) : '\0') 

再上线342:

case 'G': 
    if (Next_Letter == 'H') { 
     if (!(NOGHTOF(Look_Back_Letter(3)) || Look_Back_Letter(4) == 'H')) { 
      Phonize('F'); 
      skip_letter++; 

有人可以帮助我了解究竟是什么NOGHTOF功能为什么这个代码不正确地为“赖特”中的-gh-渲染一个F?我不是一个真正的C人,所以代码对我来说一点都不清楚。

+1

那么也许有人可以提交一个补丁到列表中并修复这个bug! – 2012-02-13 20:45:34

+0

SO需要更多这样的问题:) – 2012-02-13 21:57:59

回答

1

NOGHTOF(c)含义实际上是由代码来确定起始于线81:为了

char _codes[26] = { 
     1, 16, 4, 16, 9, 2, 4, 16, 9, 2, 0, 2, 2, 2, 1, 4, 0, 2, 4, 4, 1, 0, 0, 0, 8, 0 
    /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ 
}; 

#define ENCODE(c) (isalpha(c) ? _codes[((toupper(c)) - 'A')] : 0) 

本质上,一个值被指定为字母表中的每个字母(A = 1,B = 16,等)然后ENCODE宏检查传递的字符是否是一个字母;如果是,则返回该字母的相应代码,否则返回null字符。 (它并没有真正返回任何东西,因为这是一个宏,并在编译时被编译器替换以替换实际的调用。)

我正在阅读代码'G'的方式是这样的(没有试图明白为什么):

If current letter is G then 
    If next letter is H then 
     Take "_code" value of a letter three letters back (why?) from the _codes table and check the fifth bit (from the back, naturally) 
     If this bit is not set OR if a letter four letters back (why?) is 'H' then 
      Add 'F' to the result 
      skip one more character (letter 'H' following the 'G') 

为什么是这样的我是无法理解,我敢十分肯定有人有一个很好的理由是这样写,但似乎一个明显的错误给我。

+0

谢谢。我只是比较熟悉位级操作符。你能告诉我如何用16来清除最后4位的数字吗? – Chris 2012-02-13 21:12:30

+0

首先,我的错误是,它没有清除最后4位 - 它检查是否设置了第五位 - 我正在更新我的答案。现在,你没有处理任何数字,但只有一个字节(8位):二进制xxxxxxxx;二进制中的16是00010000;现在按位AND取两个数字的相应位,并且只有在两个位都为1时,才将相应的位设置为1来创建一个新的数字。 – 2012-02-13 21:28:28

+0

对,我得到了&运算符所做的。我想它是检查是否第5位被设置,但被你的答案弄糊涂了。谢谢你清理那个。话虽如此,是的,我也很不确定为什么检查G之前的第三个字母是否是('B','D','H')会使-gh-无声。也许那里的原始编码器是以这种方式选择几个词语(我得到的树枝和面团,但是霍夫?),但毫无疑问,代码是不正确的/错误的地狱。感谢您的额外见解。 – Chris 2012-02-13 21:38:07