2012-02-13 74 views
7

我正在測試C#的metaphone實現並將其結果與PHP中內置的metaphone()函數進行比較。但是,我遇到了一個錯誤(它是previously documented in PHP's issue tracker並在a mailing list上討論過),但我試圖瞭解他們錯誤背後的C代碼,這是爲了我個人的興趣。PHP metaphone實現bug

基本上,根據metaphone算法,大多數-gh-的實例應該呈現爲沉默。在「萊特」的具體測試情況下,我希望(和我自己的算法生成)「RT」的變音鍵

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

Result: RT 

然而,PHP的音位函數返回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功能爲什麼這個代碼不正確地爲「賴特」中的-gh-渲染一個F?我不是一個真正的C人,所以代碼對我來說一點都不清楚。

+1

那麼也許有人可以提交一個補丁到列表中並修復這個bug! – 2012-02-13 20:45:34

+0

SO需要更多這樣的問題:) – 2012-02-13 21:57:59

回答

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

謝謝。我只是比較熟悉位級操作符。你能告訴我如何用16來清除最後4位的數字嗎? – Chris 2012-02-13 21:12:30

+0

首先,我的錯誤是,它沒有清除最後4位 - 它檢查是否設置了第五位 - 我正在更新我的答案。現在,你沒有處理任何數字,但只有一個字節(8位):二進制xxxxxxxx;二進制中的16是00010000;現在按位AND取兩個數字的相應位,並且只有在兩個位都爲1時,纔將相應的位設置爲1來創建一個新的數字。 – 2012-02-13 21:28:28

+0

對,我得到了&運算符所做的。我想它是檢查是否第5位被設置,但被你的答案弄糊塗了。謝謝你清理那個。話雖如此,是的,我也很不確定爲什麼檢查G之前的第三個字母是否是('B','D','H')會使-gh-無聲。也許那裏的原始編碼器是以這種方式選擇幾個詞語(我得到的樹枝和麪團,但是霍夫?),但毫無疑問,代碼是不正確的/錯誤的地獄。感謝您的額外見解。 – Chris 2012-02-13 21:38:07