Ошибка реализации метафона PHP - PullRequest
7 голосов
/ 14 февраля 2012

Я тестирую реализацию метафона для C # и сравниваю ее результаты со встроенной функцией metaphone () из PHP. Однако я столкнулся с ошибкой (которая ранее была задокументирована в трекере проблем PHP и обсуждалась в списке рассылки ), но я пытаюсь понять код C, стоящий за их ошибка для моего личного интереса.

По сути, в соответствии с алгоритмом метафона, большинство экземпляров -gh- должны быть переведены в молчание. В конкретном тестовом примере «wright» я ожидаю (и генерирую с помощью моего собственного алгоритма) метафоновую клавишу «RT»

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

Result: RT

Однако функция метафона PHP возвращает RFT. Ясно, что он преобразует -gh- в F, как если бы он был в конце слова (например, «грубый»), но в случае слова «wright» это неверно, потому что -gh- не прийти в конце слова. Глядя на файл metaphone.c в дистрибутиве исходного кода PHP, я вижу несколько ключевых вещей:

/* 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 и почему этот код неправильно отображает F для -gh- in "wright"? Я на самом деле не парень С, так что код мне совсем не понятен.

1 Ответ

1 голос
/ 14 февраля 2012

Значение 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')

Почему это так, что я не знаю, но я вполне уверен, что у кого-то была веская причина написать это так, но это кажется очевидной ошибкойя.

...