7

我正在测试 C# 的 metaphone 实现,并将其结果与 PHP 的内置 metaphone() 函数进行比较。但是,我遇到了一个错误(以前记录在 PHP 的问题跟踪器中并在邮件列表中讨论过),但出于个人兴趣,我正在尝试了解其错误背后的 C 代码。

基本上,根据变音位算法,-gh- 的大多数实例应该被渲染为静音。在“wright”的具体测试用例中,我期望(并用我自己的算法生成)“RT”的变音键

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

Result: RT

但是,PHP 的变音位函数返回 RFT。显然,它将 -gh- 转换为 F,就好像它位于单词的末尾(例如“rough”),但对于单词“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 函数的确切作用以及为什么这段代码错误地为“wright”中的 -gh- 呈现 F 吗?我不是真正的 C 人,所以代码对我来说根本不清楚。

4

1 回答 1

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

为什么会这样,但我无法理解,我很确定有人有充分的理由这样写,但对我来说这似乎是一个明显的错误。

于 2012-02-13T21:03:28.783 回答