我正在测试C#的metaphone实现,并将其结果与PHP内置的metaphone()函数进行比较。但是,我遇到了一个错误(previously documented in PHP's issue tracker并在a mailing list上讨论过),但我正在尝试根据自己的个人兴趣了解其错误背后的C代码。
基本上,根据metaphone算法,大多数-gh-的实例应该是静默的。在“wright”的具体测试用例中,我期望(并使用我自己的算法生成)一个“RT”的互联网密钥
"wr" => R
"i" => ignored
"gh" => ignored
"t" => T
Result: RT
但是,PHP的metaphone功能会返回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函数到底是做什么的,以及为什么这段代码错误地为“wright”中的-gh-呈现F?我不是一个真正的C家伙,所以代码对我来说根本不清楚。
答案 0 :(得分: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')
为什么它会超出我的范围,我很确定有人有充分的理由以这种方式写它,但这对我来说似乎是一个明显的错误。