2012-02-13 27 views
7

Estoy probando la implementación de metaphon para C# y comparando sus resultados con la función metaphone incorporada() de PHP. Sin embargo, he encontrado un error (que es previously documented in PHP's issue tracker y discutido en a mailing list), pero estoy tratando de entender el código C detrás de su error para mi propio interés personal.Error de implementación PHP metaphon

Básicamente, de acuerdo con el algoritmo de metafonía, la mayoría de las instancias de -gh- se deben silenciar. En el caso de la prueba específica de "Wright", espero (y generar con mi propio algoritmo) una clave metaphone de "RT"

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

Result: RT 

Sin embargo, la función de PHP metaphone vuelve RFT. Claramente, está convirtiendo el -gh- en una F, como si estuviera al final de una palabra (por ejemplo, "rough"), pero en el caso de la palabra "wright", esto es incorrecto, porque -gh- does no venido al final de la palabra Mirando el archivo metaphone.c en la distribución fuente PHP, veo algunas cosas claves:

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

Y a continuación, en la línea 342:

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

Puede alguien ayudarme a entender qué es exactamente la función NOGHTOF qué y por qué este código está representando incorrectamente una F para el -gh- en "wright"? No soy realmente un tipo C, por lo que el código no está del todo claro para mí.

+1

¡Entonces quizás alguien pueda enviar un parche a la lista y solucionar este error! –

+0

SO necesita más preguntas como esta :) –

Respuesta

1

El significado de NOGHTOF(c) se determina en realidad por el código que empieza en la línea 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) 

Esencialmente, se le asigna un valor para cada letra del alfabeto en orden (A = 1, B = 16, etc .) Luego, la macro ENCODE comprueba si el carácter pasado es una letra; si es así, devuelve el código correspondiente para esa letra; de lo contrario, devuelve el carácter null. (Realmente no devuelve nada, ya que es una macro y el compilador la sustituye en tiempo de compilación para reemplazar la llamada real).

La manera en que estoy leyendo el código para 'G' es esto (sin intentar entender por qué):

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

¿Por qué es así está más allá de mí, sin embargo, estoy bastante seguro de que alguien tenía una buena razón para escribir de esta manera, pero parece un error obvio para mí.

+0

Gracias. Solo estoy familiarizado con los operadores de nivel de bits. ¿Puede decirme exactamente cómo 'AND' un número con 16 borra los últimos 4 bits? – Chris

+0

Primero, mi error, no está borrando los últimos 4 bits - verifica si el quinto bit está configurado - estoy actualizando mi respuesta. Ahora, no está tratando con ningún número, sino solo con un byte (8 bits): xxxxxxxx en binario; 16 en binario es 00010000; ahora en modo bit Y toma los bits correspondientes de dos números y crea un nuevo número configurando el bit correspondiente en 1 solo si ambos bits son 1. –

+0

Bien, obtuve lo que hace el operador &. Pensé que estaba comprobando si el bit 5 estaba configurado, pero me confundió tu respuesta. Gracias por aclarar eso. Habiendo dicho eso, sí, también estoy muy inseguro de por qué comprobar si la tercera letra antes del G es ('B', 'D', 'H') haría que el -gh- permanezca en silencio. Tal vez el codificador original estaba apuntando a algunas palabras seleccionadas de esta manera (la masa y la pasta que obtengo, pero ¿verdad?), Pero sin duda el código es incorrecto/con errores como el infierno. Gracias por la información adicional. – Chris