¿Hay una mejor manera de deshacerse de los acentos y hacer que esas letras sean regulares, aparte de usar el String.replaceAll()
método y reemplazar las letras una por una? Ejemplo:
Entrada: orčpžsíáýd
Salida: orcpzsiayd
No necesita incluir todas las letras con acentos como el alfabeto ruso o el chino.
java
string
diacritics
Martín
fuente
fuente
string.replaceAll("\\p{M}", "")
. Consulte regular-expressions.info/unicode.html para obtener más información.A partir de 2011, puede usar Apache Commons StringUtils.stripAccents (input) (desde 3.0):
Nota:
La respuesta aceptada (Erick Robertson) no funciona para Ø o Ł. Apache Commons 3.5 tampoco funciona para Ø, pero funciona para Ł. Después de leer el artículo de Wikipedia para Ø , no estoy seguro de que deba reemplazarse con "O": es una letra separada en noruego y danés, alfabetizada después de "z". Es un buen ejemplo de las limitaciones del enfoque de "acentos de tira".
fuente
La solución de @ virgo47 es muy rápida, pero aproximada. La respuesta aceptada usa Normalizer y una expresión regular. Me preguntaba qué parte del tiempo tomó Normalizer versus la expresión regular, ya que la eliminación de todos los caracteres no ASCII se puede hacer sin una expresión regular:
Se pueden obtener pequeñas aceleraciones adicionales escribiendo en un char [] y no llamando aCharArray (), aunque no estoy seguro de que la disminución en la claridad del código lo merezca:
Esta variación tiene la ventaja de la corrección de la que usa Normalizer y algo de la velocidad de la que usa una tabla. En mi máquina, esta es aproximadamente 4 veces más rápida que la respuesta aceptada, y 6.6x a 7x más lenta que @ virgo47 (la respuesta aceptada es aproximadamente 26 veces más lenta que @ virgo47 en mi máquina).
fuente
out
debe redimensionarse para que coincida con el número de caracteres válidosj
antes de que se use para construir el objeto de cadena.flattenToAscii
crea el resultado "aa .." donde los puntos representan \ u0000. Eso no es bueno. La primera pregunta es: ¿cómo representar los caracteres "no normalizables"? Digamos que será?, O podemos dejar NULL char allí, pero en cualquier caso tenemos que preservar la posición correcta de estos (al igual que lo hace la solución regex). Para esto, el if en el bucle debe ser algo así como:if (c <= '\u007F') out[j++] = c; else if (Character.isLetter(c)) out[j++] = '?';
lo ralentizará un poco, pero debe ser correcto en primer lugar. ;-)isLetter
) no es la correcta, pero no encontré nada mejor. No soy un experto en Unicode, por lo que no sé cómo identificar mejor la clase del carácter único que reemplaza al carácter original. Las letras funcionan bien para la mayoría de las aplicaciones / usos.EDITAR: Si no está atascado con Java <6 y la velocidad no es crítica y / o la tabla de traducción es demasiado limitante, use la respuesta de David. El punto es usar
Normalizer
(introducido en Java 6) en lugar de la tabla de traducción dentro del bucle.Si bien esta no es una solución "perfecta", funciona bien cuando conoce el rango (en nuestro caso Latin1,2), funcionó antes de Java 6 (aunque no es un problema real) y es mucho más rápido que la versión más sugerida (puede o puede no sea un problema):
Las pruebas en mi HW con JDK de 32 bits muestran que esto realiza la conversión de àèéľšťč89FDČ a aeelstc89FDC 1 millón de veces en ~ 100 ms, mientras que el modo Normalizador lo hace en 3.7 s (37 veces más lento). En caso de que sus necesidades estén relacionadas con el rendimiento y conozca el rango de entrada, esto puede ser para usted.
Disfruta :-)
fuente
trabajó para mi. La salida del fragmento anterior da "aee", que es lo que quería, pero
no hizo ninguna sustitución.
fuente
Dependiendo del idioma, puede que no se consideren acentos (que cambian el sonido de la letra), sino signos diacríticos.
https://en.wikipedia.org/wiki/Diacritic#Languages_with_letters_containing_diacritics
"Bosnio y croata tienen los símbolos č, ć, đ, š y ž, que se consideran letras separadas y se enumeran como tales en los diccionarios y otros contextos en los que las palabras se enumeran según el orden alfabético".
Eliminarlos podría estar cambiando inherentemente el significado de la palabra, o cambiar las letras a letras completamente diferentes.
fuente
Me he enfrentado al mismo problema relacionado con la verificación de igualdad de cadenas. Una de las cadenas de comparación tiene el código de caracteres ASCII 128-255 .
Use el siguiente código para diferentes espacios y sus códigos de bytes:
wiki for List_of_Unicode_characters
➩ Transliteraciones ASCII de cadena Unicode para Java.
unidecode
➩ utilizando
Guava
: Google CoreLibraries for Java
.Para la codificación de URL para el espacio, use Guava laibrary.
Overcome Para superar este problema utilizado
String.replaceAll()
con algunosRegularExpression
.➩ Usando java.text.Normalizer.Form . Esta enumeración proporciona constantes de las cuatro formas de normalización Unicode que se describen en el Anexo estándar Unicode # 15 - Formularios de normalización Unicode y dos métodos para acceder a ellos.
Prueba de cadenas y salidas en diferentes enfoques como ➩ Unidecode, Normalizer, StringUtils .
El uso de Unidecode es el
best choice
, Mi código final que se muestra a continuación.fuente
Sugiero Junidecode . Manejará no solo 'Ł' y 'Ø', sino que también funciona bien para la transcripción de otros alfabetos, como el chino, al alfabeto latino.
fuente
La solución @David Conrad es la más rápida que intenté usar el Normalizador, pero tiene un error. Básicamente, elimina los caracteres que no son acentos, por ejemplo, los caracteres chinos y otras letras como æ, se eliminan todos. Los caracteres que queremos eliminar son marcas sin espacios, caracteres que no ocupan un ancho adicional en la cadena final. Estos caracteres de ancho cero básicamente terminan combinados en algún otro carácter. Si puede verlos aislados como un personaje, por ejemplo así `, supongo que se combina con el carácter de espacio.
fuente
Una de las mejores maneras de usar regex y Normalizer si no tiene una biblioteca es:
Esto es más eficiente que replaceAll ("[^ \ p {ASCII}]", "")) y si no necesita signos diacríticos (como su ejemplo).
De lo contrario, debe usar el patrón p {ASCII}.
Saludos.
fuente
Creo que la mejor solución es convertir cada carácter a HEX y reemplazarlo con otro HEX. Es porque hay 2 tipos de Unicode:
Por ejemplo, "Ồ" escrito por Unicode compuesto es diferente de "Ồ" escrito por Unicode precompuesto. Puede copiar mis caracteres de muestra y convertirlos para ver la diferencia.
Desarrollé esta función para que algunos bancos conviertan la información antes de enviarla al banco central (por lo general, no son compatibles con Unicode) y me enfrenté a este problema cuando los usuarios finales usan la tipificación Unicode múltiple para ingresar los datos. Entonces, creo, convertir a HEX y reemplazarlo es la forma más confiable.
fuente
En caso de que alguien esté luchando por hacer esto en Kotlin, este código funciona de maravilla. Para evitar inconsistencias, también uso .toUpperCase y Trim (). entonces lanzo esta función:
}
para usar estos divertidos, lanza el código de esta manera:
fuente