SOUNDEX, función que ha estado presente en Oracle desde tiempos remotos, es un clásico algoritmo fonético utilizado para indexar nombres propios, asociando palabras que suenen igual a pesar de ocasionales diferencias en su escritura.
El algoritmo SOUNDEX fue concebido teniendo en cuenta la fonética del idioma inglés, por lo que hace inadecuado su uso en el castellano. Realizando adaptaciones propias del idioma español, implementé una versión en PL/SQL llamada SOUNDESP, la cual respeta la esencia del algoritmo original.
Los pasos básicos son:
- Retener la primera letra de la cadena. Tener en cuenta las letras dobles como CH y LL.
- Remover todas las ocurrencias de las letras siguientes a partir de la segunda posición: a, e, i, o, u, h, w, y (cuando suena como vocal i )
- Asignar números a las siguientes letras (luego de la primera):
- b, f, p, v = 1
- c, g, j, k, q, s, x, z = 2
- d, t = 3
- l = 4
- m, n = 5
- r = 6
- ll, y, ch = 7
- Si hay números consecutivos, dejar solamente uno en la serie.
- Retornar los cuatro primeros caracteres, si son menos de cuatro completar con ceros.
SOUNDESP es un proyecto abierto y es bienvenido cualquier comentario para mejorar su implementación.
NOTA: Para descargar el código correctamente, haga click derecho y elija Guardar destino
Ver también:
Wikipedia: Soundex

11 comentarios:
Hola,
antes de nada dar las gracias por este package, muy útil, pero le veo un par de bugs así de primeras:
1. Falla si la cadena de entrada es de más de 30 caracteres.
2. Prueba la palabra "Bahía" verás que falla porque elimina la H y las vocales y nos quedamos con una palabra de una letra que falla en la función eli_ady
Espero sea de utilidada
¿Lo vas a solventar?
Gracias
Roberto, ya fueron solucionados esos bugs, la nueva versión ya está disponible.
Muchas gracias y cualquier otro comentario será más que bienvenido!
Saludos
Gracias por la rapidez.
Se me olvidó comentar un fallo que corregí sobre la marcha, he tenido que modificar la función eli_acc para que funcione con algunos casos por esta:
FUNCTION eli_acc(p_pal IN VARCHAR2) RETURN VARCHAR2 AS
BEGIN
RETURN TRANSLATE(LTRIM(UPPER(p_pal),'H'),'ÑñáéíóúÁÉÍÓÚ','NNAEIOUAEIOU');
END eli_acc;
Espero sea de utilidad.
Saludos
Aunque lo más correcto sería esto:
FUNCTION eli_acc(p_pal IN VARCHAR2) RETURN VARCHAR2 AS
BEGIN
RETURN TRANSLATE(LTRIM(UPPER(p_pal),'H'),'ÑÁÉÍÓÚ','NAEIOU');
END eli_acc;
ya que está en mayúsculas el convertir las minúsculas carece de sentido.
Saludos
Creo que esto no acaba de ir del todo bien, estoy probandolo con diversas cadenas y me da resultados de lo más extraños. Fijate:
Aldeyuso|A437
Aguilar de Campos|AG46
Aguilar de Campos|AG46
La Abadía|L 13
Abrojo|A167
Los Álamos|L2 4
Los Álamos|L2 4
Aceñas de Zofraguillas|A252
Las Aceñas|L2 2
Se supone que los resultados deberían tener el formato \w\d{3}
Estoy un poco pesadito, pero gracias a esto podemos conseguir un package muy sólido.
Te comento otra cosa, cuando pasamos una cadena de 30 caracteres o más sin ningún tipo de acento como por ejemplo:
'Esto es una prueba de mas de 30 caracteres'
Todo va bien, pero surge un problema cuando uno o varios de esos caracteres en los primeros 30 está acentuado porque ese caracter ocupa 2 bytes, por ejemplo:
'Esto es una prueba de más de 30 caracteres'
He acentuado la 'a' de más y claro ahora al cortar y quedarlo en 30:
'Esto es una prueba de más de 3'
Internamente están contando 31 y falla, por lo cual habría que hacer una de estas opciones:
a) Quitar los acentos antes de cortar la cadena.
b) Tener en cuenta que la cadena medirá 30 + número de caracteres especiales.
Espero que sirva.
Saludos
Roberto, muy valiosos comentarios,
hay una nueva versión disponible que corrige lo siguiente:
- Tomo tu sugerencia sobre TRANSLATE en eli_acc y además elimino espacios para evitar resultados como los que reportaste
- Elimino caracteres multibyte antes de cortar a 30 la cadena de caracteres tal como sugieres
Gracias y saludos!
Amigos no se si será por mi desconocimiento de la fonética de nuestro idioma pero me parece que en la función
cnv_dos se debería remplazar la LL por Y de esta forma seria lo mismo YANDER que LLANDER.
corríjanme si me equivoco.
Es muy correcto, y quedó corregido ese detalle. Ahora YANDER y LLANDER retornan el mismo valor.
Muchas gracias!
Saludos
Quisiera que me explicaran cual es la idea de retener la primera letra y luego concatenársela a la cadena final,que se logra con esto??.
Publicar un comentario en la entrada