2012-02-13 11 views
7

私はC#用のメタフォン実装をテストしており、その結果をPHPの組み込みmetaphone()関数と比較しています。しかし、私はバグ(previously documented in PHP's issue trackera mailing listで議論されています)に出くわしましたが、私自身の個人的な興味のためにバグの背後にあるCコードを理解しようとしています。PHPメタフォン実装のバグ

基本的に、メタホンアルゴリズムによれば、-gh-のほとんどのインスタンスはサイレントにする必要があります。 「RT」のmetaphoneのキー「ライト」の具体的なテストケースでは、私が期待して(と私自身のアルゴリズムで生成)

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

Result: RT 

しかし、PHPのmetaphoneの機能は、RFTを返します。明らかに、単語の終わりにあるかのように、-gh-をFに変換しますが、単語 "wright"の場合、-gh-が実行するので、これは正しくありません。言葉の最後に来ない。

/* 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機能を理解するのに役立ちますPHPのソース配布中metaphone.cファイルを見て、私はいくつかの重要な物事を見ますなぜこのコードが-gh- in "wright"のためにFを間違ってレンダリングしているのですか?私は本当にCの男ではないので、コードは私にはっきりと分かりません。

+1

おそらく誰かがリストにパッチを提出し、このバグを修正することができます! –

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

、これはしかし、私を超えているようなぜ、私は、誰かがそれをこのように書くための良い理由があったかなり確信しているが、それは私には明らかにバグと思われます。

+0

ありがとうございます。私はビットレベルの演算子に多少慣れています。最後の4ビットを16でクリアすると、正確に 'AND'していくことができますか? – Chris

+0

まず、私の間違いは、最後の4ビットをクリアしていない - それは5番目のビットが設定されているかどうかをチェックする - 私は私の答えを更新しています。さて、あなたはどんな数でも扱わないが、バイナリでは1バイト(8ビット)xxxxxxxxのみで処理する。 16進数は00010000です。現在、ビット単位のANDは2つの数値の対応するビットを取り、両方のビットが1の場合にのみ対応するビットを1に設定することによって新しい数値を作成します。 –

+0

私はビット5がセットされているかどうかをチェックしていると思ったが、あなたの答えによって混乱した。それをクリアしていただきありがとうございます。 Gの前の3番目の文字が( 'B'、 'D'、 'H')であるかどうかを調べると、なぜサイレントになってしまうのかを確認するのは非常に不確かです。おそらく、オリジナルのコーダーは、このような方法でいくつかの選択された単語をターゲットにしていました(しかし、私は入手しましたが、ハーフ?)が、間違いなくコードは間違っています。さらなる洞察をいただきありがとうございます。 – Chris