2010-01-19 11 views
8

¿Cuál es la mejor manera de convertir una cadena de Unicode a ASCII sin cambiar su longitud (eso es muy importante en mi caso)? Además, los caracteres sin problemas de conversión deben estar en las mismas posiciones que en la cadena original. Así que una "Ä" debe convertirse a "A" y no algo críptico que tenga más caracteres.Convertir Unicode en ASCII sin cambiar la longitud de la cadena (en Java)

Editar:
@novalis - Tales símbolos (por ejemplo, de idiomas asiáticos) deberían simplemente convertirse a algunos marcadores de posición. No estoy demasiado interesado en esas palabras ni en lo que significan.

@MtnViewMark - Debo conservar el número de todos los caracteres y la posición de los caracteres disponibles ASCII bajo ninguna circunstancia.

Aquí algo más de información: Tengo algunas herramientas de minería de textos que solo pueden procesar cadenas ASCII. La mayoría del texto que debe procesarse está en inglés, pero algunos contienen caracteres que no son ASCII. No me interesan esas palabras, pero debo estar seguro de que las palabras que me interesan (las que solo contienen caracteres ASCII) se encuentran en las mismas posiciones después de la conversión de la secuencia.

+5

¿Qué pretende convertir 口水 雞 a? No sé cómo se podría expresar el concepto de pollo saliva en tres personajes ascii. – novalis

+0

No está claro, ¿está tratando de conservar el número de caracteres o el número de bytes ... o quizás el ancho de la cadena cuando se muestra? – MtnViewMark

+0

@novalis +1 para pollo saliva :-) –

Respuesta

12

Como se indica en this respuesta, el código siguiente debería funcionar:

String s = "口水雞 hello Ä"; 

    String s1 = Normalizer.normalize(s, Normalizer.Form.NFKD); 
    String regex = "[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+"; 

    String s2 = new String(s1.replaceAll(regex, "").getBytes("ascii"), "ascii"); 

    System.out.println(s2); 
    System.out.println(s.length() == s2.length()); 

salida es

??? hello A 
true 

por lo que primero eliminar las marcas diactrical, el convertido a ASCII. Los caracteres no ascii se convertirán en signos de interrogación.

+0

Gracias ... parece funcionar casi bien. Pero hay un problema con el carácter '^'. Cuando está dentro de una cadena (como "he ^^ o") falla (simplemente se elimina). – Zardoz

+0

Simplemente elimine \\ p {IsLm} \\ p {IsSk} de la expresión regular. –

+1

Si alguien quiere eliminar signos de interrogación y reducir totalmente el texto para tratar de letras básicas: "[P \\ {InBasicLatin}] +" (nótese la mayúscula P significa "No en) Probado usando:. Rrrr̈r'ŕřttẗţỳỹẙy'yýÿŷpp̈sss̈s̊s's̸śŝŞşšddd̈ďd'ḑf̈f̸ggg̈g'ģq ĝǧḧĥj̈j'ḱkk̈k̸ǩlll̈Łłẅẍcc̈c̊c'c̸Çççćĉčvv̈v'v̸bb̧ǹnn̈n̊n'ńņňñmmmm̈ m̊m̌ǵß – RedYeti

7

Utilice java.text.Normalizer.normalize() con Normalizer.Form.NFD, luego filtre los caracteres que no sean ASCII.

+0

Esto es probablemente lo que Zardoz realmente quería, aunque va a ser ineficaz para los personajes que no están en las páginas latinas. –

+0

+1 esta parece ser la mejor solución al problema (en la medida en que se puede deducir de la pregunta). –

+0

La normalización Unicode solo funcionará para los caracteres, que pueden estar compuestos por un carácter latino simple del juego de caracteres ASCII y una marca diacrítica. – jarnbjo

2

Advertencia: No sé Java. Solo un poco sobre conjuntos de personajes.

No está indicando qué conjunto de caracteres está utilizando exactamente.

Pero no importa lo que se utiliza, es imposible convertir una cadena Unicode a ASCII y conservan las posiciones de longitud y carácter originales, simplemente porque un conjunto de caracteres Unicode utilizará múltiples bytes para algunos caracteres (obviamente).

La única excepción que conozco sería una cadena UTF-8 que contiene solo caracteres ASCII: Esta cadena ya será idéntica en UTF-8 y ASCII, porque UTF-8 usa caracteres multibyte solo cuando es necesario. (No sé sobre los otros sabores Unicode, puede haber otros dinámicos).

La única solución que puedo ver es la adición de un espacio a cualquier carácter especial que fue reemplazado por un ASCII, pero que arruine la cadena (Göteborg en UTF8 tendría que convertirse en Go teborg para mantener la longitud).

Quizás desee elaborar sobre lo que quiere/necesita lograr, para que la gente aquí pueda sugerir soluciones.

+0

Java usa UTF-16 para cadenas internas, por lo que para la mayoría de los lenguajes "occidentales" comunes, el texto original y el texto "reducido en ASCII" tendrán la misma longitud (excepto la puntuación impar ocasional). –

2

Una cuestión con Normalizer es que pre Java 1.6 está en el paquete sun.text, mientras que en 1.6 está en el paquete java.text y la firma del método ha cambiado. Entonces, si su aplicación necesita ejecutarse en ambas plataformas, tendrá que usar la reflexión.

Una solución a la medida alternativa se describe como techniwue 3 here

2

Como se ha mencionado Paul Taylor: no hay problema con el uso Normalizador si necesita que el proyecto sea compilables/ejecutable en pre-1.6 y también en 1.6 y superior java . Obtendrá problemas ya que Normalizer está en paquetes diferentes (java.text.Normalizer (para 1.6) en lugar de sun.text.Normalizer (para pre-1.6)) y tiene una firma de método diferente.

Normalmente se recomienda utilizar la reflexión para invocar el método Normalizer.normalize() apropiado. (Example could be found here).
Pero si no desea reflejar el desorden en su código, puede usar icu4j library. Contiene la clase com.ibm.icu.text.Normalizer con el método normalize() que realiza el mismo trabajo que java.text.Normalizer/sun.text.Normalizer. La biblioteca de Icu tiene (debería tener) una implementación propia de Normalizer para que pueda compartir su proyecto con la biblioteca y que sea independiente de Java.
La desventaja es que la biblioteca icu es bastante grande.

Si usa la clase Normalizer solo para eliminar acentos/diacríticos de Strings, también hay otra forma. Puede utilizar Apache commons lang library (ver. 3) que contiene StringUtils con el método stripAccents():

String noAccentsString = org.apache.commons.lang3.StringUtils.stripAccents(s); 

biblioteca Lang3 probablemente utilizar la reflexión para invocar Normalizador apropiado de acuerdo a la versión de Java. Entonces, la ventaja es que no tienes un problema de reflexión en tu código.

Cuestiones relacionadas