"""Comparar por como SUENA, no por como se escribe. ## Que problema resuelve Midiendo donde se pierde el acierto salio esto: de 150 ordenes dichas, el 79 % llega a su accion, un 5 % se oye mal de verdad, y un **15 % se oye bien pero el emparejador no lo relaciona**. Mirando esos casos uno a uno, no son ordenes distintas: son la misma orden mal escrita. dijo "receta de documentos" oyo "Leceta de documentos" dijo "como van los pubs" oyo "¿Como van los poops?" dijo "abre bandcamp" oyo "Abre van Kamp" dijo "abre el drive" oyo "Abril Drive" dijo "abreme oasis" oyo "Abre mi roasis" Eso NO se arregla con embeddings: un modelo semantico ve "Leceta" como una palabra inexistente, no como "receta". Y bajar el umbral de parecido tampoco, porque el umbral esta alto por una razon —hay una cicatriz en el codigo de cuando "que carne el tiempo" se colaba en la accion del tiempo y ejecutaba lo que no era—. Lo que sirve es comparar como suena. En castellano hay unas pocas confusiones que lo explican casi todo, y son las que aplica `fonetica()`. ## Lo que NO hace No es un Soundex ni un Metaphone: esos comprimen tanto que juntan palabras que no se parecen, y aqui juntar de mas significa ejecutar la orden equivocada, que es lo peor que puede hacer esto. Se queda en las equivalencias que de verdad confunde el reconocedor de voz en castellano, y nada mas. """ import re import unicodedata # El orden importa: cada regla se aplica sobre el resultado de la anterior. REGLAS = ( # la hache no suena (r"h", ""), # b y v son el mismo sonido: "van Kamp" / "bandcamp" (r"v", "b"), # ge/gi suenan como jota (r"g([ei])", r"j\1"), # gue/gui: la u es muda (r"gu([ei])", r"g\1"), # que/qui igual, y qu -> k (r"qu([ei])", r"k\1"), (r"q", "k"), # ce/ci en seseo suenan como ese; ca/co/cu como ka (r"c([ei])", r"s\1"), (r"c", "k"), # z siempre ese (seseo): asi "poops"/"pubs" y "haz"/"has" caen juntos (r"z", "s"), # x entre vocales suena ks, pero al principio suele ser ese (r"^x", "s"), (r"x", "ks"), # ll e y son el mismo sonido para casi todo el mundo (r"ll", "y"), # w es de fuera: suena como u o como b segun la palabra; se unifica a b (r"w", "b"), # la erre doble y la simple no se distinguen al transcribir (r"rr", "r"), # la ñ se escribe de mil formas cuando el reconocedor duda (r"ñ", "n"), # las dobles no aportan: "poops" -> "pops" (r"(.)\1+", r"\1"), # las vocales finales se comen mucho; y la ese final tambien (r"s$", ""), ) def fonetica(texto: str) -> str: """Como suena, aproximadamente, para poder comparar dos oidos distintos.""" t = unicodedata.normalize("NFD", (texto or "").lower()) t = "".join(c for c in t if unicodedata.category(c) != "Mn" or c == "̃") t = unicodedata.normalize("NFC", t) t = re.sub(r"[^a-zñ\s]", " ", t) palabras = [] for p in t.split(): for patron, cambio in REGLAS: p = re.sub(patron, cambio, p) if p: palabras.append(p) return " ".join(palabras)