2010-01-19 4 views
8

Qual è il modo migliore per convertire una stringa da Unicode in ASCII senza modificarne la lunghezza (che è molto importante nel mio caso)? Anche i personaggi senza problemi di conversione devono trovarsi nelle stesse posizioni della stringa originale. Quindi un "Ä" deve essere convertito in "A" e non qualcosa di criptico che ha più caratteri.Converti Unicode in ASCII senza modificare la lunghezza della stringa (in Java)

Modifica:
@novalis - Tali simboli (ad esempio delle lingue asiatiche) devono essere convertiti in alcuni segnaposto. Non sono troppo interessato a quelle parole o al loro significato.

@MtnViewMark - Devo conservare il numero di tutti i caratteri e la posizione dei caratteri ASCII disponibili in qualsiasi circostanza.

Ecco alcune informazioni in più: dispongo di strumenti di mining di testo che possono elaborare solo stringhe ASCII. La maggior parte del testo che deve essere elaborato è in inglese, ma alcuni contengono caratteri non ASCII. Non sono interessato a queste parole, ma devo essere sicuro che le parole che mi interessano (quelle che contengono solo caratteri ASCII) sono nelle stesse posizioni dopo la conversione delle stringhe.

+5

Che cosa intendete convertire in 口水 雞? Non so come si possa esprimere il concetto di pollo saliva in tre caratteri ascii. – novalis

+0

Non è chiaro: stai cercando di conservare il numero di caratteri o il numero di byte ... o forse la larghezza della stringa quando viene visualizzata? – MtnViewMark

+0

@novalis +1 per il pollo saliva :-) –

risposta

12

Come affermato nella this risposta, il codice seguente dovrebbe funzionare:

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()); 

uscita è

??? hello A 
true 

Quindi prima rimuovere i segni diactrical, il convertito a ASCII. I caratteri non ascii diventeranno punti interrogativi.

+0

Grazie ... sembra funzionare quasi bene. Ma c'è un problema con il carattere '^'. Quando si trova all'interno di una stringa (come "he ^^ o") fallisce (viene semplicemente cancellato). – Zardoz

+0

Basta rimuovere \\ p {IsLm} \\ p {IsSk} dall'espressione regolare. –

+1

Se qualcuno vuole rimuovere punti interrogativi e ridurre completamente il testo alle lettere di base provare: "[\\ P {} InBasicLatin] +" (notare la maiuscola P significa "Non in) testata utilizzando:. 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

Utilizzare java.text.Normalizer.normalize() con Normalizer.Form.NFD, quindi filtrare i caratteri non ASCII.

+0

Questo è probabilmente ciò che Zardoz voleva davvero, anche se sarà inefficace per i caratteri che non sono nelle pagine latine. –

+0

+1 questa sembra la migliore soluzione al problema (per quanto può essere detto dalla domanda). –

+0

La normalizzazione Unicode funzionerà solo per i caratteri, che possono essere composti da un semplice carattere latino dal set di caratteri ASCII e un segno diacritico. – jarnbjo

2

Avvertenza: non conosco Java. Solo un po 'sui set di caratteri.

Non si sta indicando quale set di caratteri si sta utilizzando esattamente.

Ma non importa che si utilizza, è impossibile convertire una stringa Unicode in ASCII e mantengono le posizioni di lunghezza e carattere originali, semplicemente perché un set di caratteri Unicode userà più byte per alcuni personaggi (ovviamente).

L'unica eccezione che conosco sarebbe una stringa UTF-8 che contiene solo caratteri ASCII: questa stringa sarà già identica sia in UTF-8 che in ASCII, poiché UTF-8 utilizza caratteri multibyte solo quando necessario. (Non so degli altri sapori Unicode, potrebbero essercene altri dinamici).

L'unica soluzione che posso vedere è l'aggiunta di uno spazio per qualsiasi carattere speciale che è stato sostituito da un ASCII uno, ma che rovinare la stringa (Göteborg in UTF8 avrebbe dovuto diventare Go teborg per mantenere la lunghezza).

Forse vuoi approfondire ciò che vuoi/devi raggiungere, così le persone qui possono suggerire soluzioni alternative.

+0

Java usa UTF-16 per le stringhe internamente, quindi per le più comuni lingue "occidentali" il testo originale e il testo "ridotto in ASCII" avranno la stessa lunghezza (salvo la punteggiatura dispari occasionale). –

2

Un problema con Normalizer è che pre Java 1.6 è nel pacchetto sun.text mentre in 1.6 è nel pacchetto java.text e la firma del metodo è cambiata. Quindi se la tua applicazione dovesse funzionare su entrambe le piattaforme dovrai usare la reflection.

Una soluzione su misura alternativa è descritto come techniwue 3 here

2

Come Paul Taylor detto: non c'è problema con l'utilizzo Normalizer se è necessario il progetto di essere compilabile/eseguibile in pre-1.6 e anche in 1.6 e superiori java . Si verificheranno dei problemi poiché Normalizer è in pacchetti diversi (java.text.Normalizer (per 1.6) anziché sun.text.Normalizer (per pre-1.6)) e ha una firma metodo diversa.

In genere si consiglia di utilizzare la riflessione per richiamare il metodo Normalizer.normalize() appropriato. (Example could be found here).
Ma se non si desidera inserire il reflection-mess nel codice, è possibile utilizzare icu4j library. Contiene la classe com.ibm.icu.text.Normalizer con il metodo normalize() che esegue lo stesso lavoro di java.text.Normalizer/sun.text.Normalizer. La libreria Icu ha (dovrebbe avere) la propria implementazione di Normalizer in modo da poter condividere il progetto con la libreria e che dovrebbe essere java-independent.
Lo svantaggio è che la libreria icu è piuttosto grande.

Se si utilizza la classe Normalizer solo per rimuovere accenti/segni diacritici da Stringhe, c'è anche un altro modo. È possibile utilizzare Apache commons lang library (ver. 3) che contiene StringUtils con metodo stripAccents():

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

biblioteca Lang3 probabilmente utilizzare la reflection per richiamare adeguata Normalizer in base alla versione di Java. Quindi il vantaggio è che non hai problemi di riflessione nel codice.