2012-02-13 14 views
7

Testuję implementację metafonu dla języka C# i porównywanie jej wyników z wbudowaną funkcją metaphone() z PHP. Jednak natknąłem się na błąd (który jest previously documented in PHP's issue tracker i omówiony na a mailing list), ale staram się zrozumieć kod C za ich błędów dla mojego osobistego zainteresowania.Błąd implementacji metafonu PHP

Zasadniczo, zgodnie z algorytmem metafonowym, większość przypadków -gh- powinno być cichych. W konkretnym przypadku testowego „Wright”, oczekuję (i generować z mojego własnego algorytmu) klucza Metaphone z „RT”

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

Result: RT 

Jednak funkcja Metaphone PHP zwraca RFT. Najwyraźniej konwertuje -gh- na F, jak gdyby znajdowało się na końcu słowa (np. "Szorstki"), ale w przypadku słowa "wright" jest to niepoprawne, ponieważ -gh- nie przychodzi na końcu tego słowa. Patrząc na pliku metaphone.c w źródłowej dystrybucji PHP, widzę kilka kluczowych rzeczy:

/* 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') 

a następnie na linii 342:

case 'G': 
    if (Next_Letter == 'H') { 
     if (!(NOGHTOF(Look_Back_Letter(3)) || Look_Back_Letter(4) == 'H')) { 
      Phonize('F'); 
      skip_letter++; 

Czy ktoś może mi pomóc zrozumieć, co dokładnie funkcję NOGHTOF robi i dlaczego ten kod niepoprawnie renderuje F dla -gh- w "wright"? Naprawdę nie jestem facetem w C, więc kod nie jest dla mnie jasny.

+1

Wtedy może ktoś może przesłać łatkę do listy i naprawić ten błąd! –

+0

SO potrzebuje więcej pytań takich jak to :) –

Odpowiedz

1

Znaczenie NOGHTOF(c) faktycznie zależy od kodu rozpoczynającego się od linii 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) 

Zasadniczo wartość jest przypisany do każdej z liter alfabetu, w celu (a = 1, B = 16, etc. .) Następnie makro sprawdza, czy przekazany znak jest literą; jeśli tak, zwraca odpowiedni kod dla tej litery, w przeciwnym razie zwraca znak null. (Tak naprawdę nic nie zwraca, ponieważ jest to makro i jest zastępowane przez kompilator w czasie kompilacji w celu zastąpienia faktycznego połączenia.)

Sposób w jaki odczytuję kod dla 'G' jest tym (bez próbowania zrozumieć, dlaczego):

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

Dlaczego to jest jak to jest poza mną, choć jestem pewien, że ktoś miał dobry powód, aby napisać to w ten sposób, ale wydaje się oczywisty błąd do mnie.

+0

Dzięki. Jestem nieco obeznany z operatorami bitowymi. Czy możesz mi powiedzieć, jak dokładnie "ORAZ liczba z 16 usuwa ostatnie 4 bity? – Chris

+0

Po pierwsze, mój błąd, to nie wyczyszczenie ostatniego 4-bitowego - sprawdza, czy ustawiony jest piąty bit - aktualizuję moją odpowiedź. Teraz nie masz do czynienia z żadną liczbą, ale tylko z jednym bajtem (8 bitów): xxxxxxxx w binarnym; 16 w systemie binarnym to 00010000; teraz bitowe ORAZ pobiera odpowiednie bity z dwóch liczb i tworzy nową liczbę przez ustawienie odpowiedniego bitu na 1 tylko wtedy, gdy oba bity są 1. –

+0

Dobrze, mam to, co robi operator &. Doszedłem do wniosku, że sprawdzałem, czy bit 5 został ustawiony, ale była zmylona twoją odpowiedzią. Dzięki za wyczyszczenie tego. Powiedziawszy to, tak, jestem również bardzo pewien, dlaczego sprawdzenie, czy trzecia litera przed literą G ("B", "D", "H") sprawi, że -gh- cichy. Być może oryginalny koder był ukierunkowany na kilka słów w ten sposób (konar i ciasto dostałem, ale hough?), Ale bez wątpienia kod jest niepoprawny/wadliwy jak diabli. Dzięki za dodatkowy wgląd. – Chris