c-PHP隐喻实现错误


c - PHP metaphone implementation bug

我正在测试C#的一个变音实现,并将其结果与PHP内置的变音()函数进行比较。然而,我遇到了一个bug(之前在PHP的问题跟踪器中记录了这个bug,并在邮件列表中进行了讨论),但出于我个人的兴趣,我正在努力理解它们bug背后的C代码。

基本上,根据隐喻算法,-gh-的大多数实例都应该被静音。在"wright"的特定测试用例中,我期望(并使用自己的算法生成)"RT"的隐喻密钥

"wr" => R
"i"  => ignored
"gh" => ignored
"t"  => T
Result: RT

然而,PHP的变音函数返回RFT。很明显,它将-gh-转换为F,就好像它在一个单词的末尾(例如"rough"),但就"wright"一词而言,这是不正确的,因为-gh-不在单词的末尾。查看PHP源代码发行版中的变音.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函数到底是做什么的吗?为什么这段代码错误地为"wright"中的-gh-渲染了一个F?我不是一个真正的C族,所以代码对我来说一点也不清楚。

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')

我不知道为什么会这样,我确信有人有充分的理由这样写,但对我来说这似乎是一个明显的错误。