2015-02-27 12 views
11

che sto cercando di dividere tutti i caratteri cinesi da una stringa, ma ho urtato una situazione strana per il personaggiocarattere singolo cinese determinato come lunghezza 2 in Java/Scala String

scala> "" 
res1: String = 

scala> res1.length 
res2: Int = 2 

scala> res1.getBytes 
res3: Array[Byte] = Array(-16, -91, -111, -82) 

scala> res1(0) 
res4: Char = ? 

scala> res1(1) 
res5: Char = ? 

Si tratta di un singolo carattere, ma Java/Scala lo determina come due caratteri sconosciuti. E di solito vedo il carattere cinese prendere tre byte in UTF-8, ma questo personaggio ne richiede quattro.

Quindi, non posso dividere una stringa e trovare questo singolo carattere. Ancora peggio, quando si utilizza myString.replaceAll("[^\\p{script=Han}]", "") per escludere tutti i caratteri non cinesi, la seconda parte viene sostituita e diventa una stringa non valida.

C'è qualche soluzione a questo? Sto usando openjdk-8-jdk su Ubuntu.

+8

Questo è chiamato un [coppia di surrogati] (http://www.ibm.com/developerworks/library/j-unicode /) (come puoi confermare con 'Character.isSurrogatePair (res1 (0), res1 (1))'). –

risposta

8

Per lunghezza si dovrebbe usare

string.codePointCount(0, string.length()); 

Per la sostituzione è consigliabile evitare espressioni regolari, che è basata su char. È possibile scrivere un ciclo basandosi su String#offsetByCodePoints() e rimuovere manualmente i caratteri in base a String.codePointAt() e Character.isIdeographic().

-3

Probabile che questo carattere non sia valido o non supportato in UTF-8 ma supportato in UTF-16, risultando in alcune incompatibilità tra JVM e Scala shell. Il tuo sistema è grande o little-endian? Potresti anche provare ad ottenere il codice Unicode del personaggio e controllare se è UTF-8 o UTF-16. Inoltre, il cinese ha composto lettere come Kanji giapponese e Furigana, quindi potrebbe anche far parte del tuo problema.

+0

Tutti i caratteri UTF-16 sono ugualmente supportati in UTF-8. – bmargulies

-2

Penso che si voglia sostituire/dividere la stringa. Cosa si può fare senza conoscere la lunghezza della stringa. Perché java prende la sequenza di stringhe anche per sostituire un particolare char o una sequenza di caratteri in una stringa. Per esempio: class Test {-`public

public static void main(String[] args) { 


    String s=""; 
    System.out.println(s.replace("", "k")); 

} 
} 

` E se si vuole dividere la stringa per poi andare stringtokenizer.For ad esempio: -

StringTokenizer st= new StringTokenizer("your sentence or String","the problematic char/string"); 
1

Il supporto Unicode della libreria standard Java precede lo standard corrente e come tale il supporto per caratteri astrali (non BMP) è ... limitato; diverse API le tratteranno come le singole coppie di surrogati che hai visto. Se stai facendo una vasta manipolazione delle stringhe, potrebbe essere meglio usare ICU4J, che a mio avviso offre regex con pieno supporto Unicode.

3

Si è verificata una coppia surrogata. Quel personaggio è U+2546E, che come vedi, è molto più grande di 2^16. È rappresentato in una stringa Java o Scala come sequenza 0xD855 0xDC6E.

Se si desidera una libreria regex che gestisca questo tipo di cose in modo trasparente, capita di sapere dove trovarne uno: TCL regex ported to Java. Se non si desidera andare lì, è necessario utilizzare i metodi Code Point di String e Character in java per navigare.

0

Sulla base @ risposta di Marko, ecco un esempio per dividere una stringa:

scala> val x = "硓abc" 
x: String = 硓abc 

scala> (0 to x.codePointCount(0, x.length)).map(c => x.offsetByCodePoints(0, c)).sliding(2).map(w => x.substring(w.head, w.last)).toList 
res1: List[String] = List(硓, , a, b, c) 

E per determinare se ogni personaggio è un CJKV:

scala> (0 until x.codePointCount(0, x.length)).map(c => x.offsetByCodePoints(0, c)).map(i => Character.isIdeographic(x.codePointAt(i))).toList 
res2: List[Boolean] = List(true, true, false, false, false) 
+0

ciao, è Java1.8? Se utilizzo java 1.7, quale dovrebbe essere la sintassi o qualsiasi altro metodo ?? –

Problemi correlati