7

私はC#のメタフォンの実装をテストし、その結果をPHPの組み込みのmetaphone()関数と比較しています。ただし、バグ(以前はPHPの課題追跡システムに文書化されてメーリングリストで説明されていました)に遭遇しましたが、個人的な興味のために、バグの背後にあるCコードを理解しようとしています。

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

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

Result: RT

ただし、PHPのメタフォン関数はRFTを返します。明らかに、それは単語の終わりにあるかのように-gh-をFに変換します(たとえば「ラフ」)が、単語「ライト」の場合、-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の人ではないので、コードは私にはまったくわかりません。

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 に答える