2012-02-15 16 views
8

Dato il seguente codice:Come analizzare la rappresentazione UTF-8 in String in Java?

String tmp = new String("\\u0068\\u0065\\u006c\\u006c\\u006f\\u000a"); 

String result = convertToEffectiveString(tmp); // result contain now "hello\n" 

Condivide la JDK già forniscono alcune classi per fare questo? C'è un libray che fa questo? (preferibilmente sotto controllo)

Ho provato con ByteArrayOutputStream senza successo.

+3

Questo non è UTF-8; è solo una stringa che contiene la rappresentazione di escape Unicode. –

risposta

3

Questo funziona, ma solo con ASCII. Se si utilizzano caratteri unicode al di fuori dell'intervallo ASCC, si avranno problemi (dato che ogni carattere viene inserito in un byte, anziché una parola completa consentita da UTF-8). Puoi eseguire il typecast qui sotto perché sai che l'UTF-8 non supererà un byte se hai garantito che l'input è fondamentalmente ASCII (come dici nei tuoi commenti).

package sample; 

import java.io.UnsupportedEncodingException; 

public class UnicodeSample { 
    public static final int HEXADECIMAL = 16; 

    public static void main(String[] args) { 

     try { 
      String str = "\\u0068\\u0065\\u006c\\u006c\\u006f\\u000a"; 

      String arr[] = str.replaceAll("\\\\u"," ").trim().split(" "); 
      byte[] utf8 = new byte[arr.length]; 

      int index=0; 
      for (String ch : arr) { 
       utf8[index++] = (byte)Integer.parseInt(ch,HEXADECIMAL); 
      } 

      String newStr = new String(utf8, "UTF-8"); 
      System.out.println(newStr); 

     } 
     catch (UnsupportedEncodingException e) { 
      // handle the UTF-8 conversion exception 
     } 
    } 
} 

Ecco un'altra soluzione che risolve il problema di lavorare solo con caratteri ASCII. Funzionerà con qualsiasi carattere Unicode nella gamma UTF-8 invece che ASCII solo nei primi 8 bit dell'intervallo. Grazie alla menzogna per le domande. Mi hai fatto pensare di più al problema e alla soluzione.

package sample; 

import java.io.UnsupportedEncodingException; 
import java.util.ArrayList; 

public class UnicodeSample { 
    public static final int HEXADECIMAL = 16; 

    public static void main(String[] args) { 

     try { 
      String str = "\\u0068\\u0065\\u006c\\u006c\\u006f\\u000a\\u3fff\\uf34c"; 

      ArrayList<Byte> arrList = new ArrayList<Byte>(); 
      String codes[] = str.replaceAll("\\\\u"," ").trim().split(" "); 

      for (String c : codes) { 

       int code = Integer.parseInt(c,HEXADECIMAL); 
       byte[] bytes = intToByteArray(code); 

       for (byte b : bytes) { 
        if (b != 0) arrList.add(b); 
       } 
      } 

      byte[] utf8 = new byte[arrList.size()]; 
      for (int i=0; i<arrList.size(); i++) utf8[i] = arrList.get(i); 

      str = new String(utf8, "UTF-8"); 
      System.out.println(str); 
     } 
     catch (UnsupportedEncodingException e) { 
      // handle the exception when 
     } 
    } 

    // Takes a 4 byte integer and and extracts each byte 
    public static final byte[] intToByteArray(int value) { 
     return new byte[] { 
       (byte) (value >>> 24), 
       (byte) (value >>> 16), 
       (byte) (value >>> 8), 
       (byte) (value) 
     }; 
    } 
} 
+1

Cosa sono "Caratteri Unicode diversi da UTF-8"? Come può un carattere Unicode/UTF-8 essere "inserito in un byte"? Non so se intendi la cosa giusta e non la esprimi abbastanza chiaramente, ma che si legge per lo più in modo sbagliato. – deceze

+0

Se si utilizza un set di caratteri Unicode diverso nella stringa "str" ​​diversa da UTF-8, questo codice potrebbe non funzionare. UTF-8 usa ancora 8 bit, in cui altri set di caratteri Unicode possono (probabilmente) utilizzare più di 8 bit (tutti invece 16 bit). http://www.joelonsoftware.com/articles/Unicode.html – jmq

+0

Ovviamente, in generale, questo codice non è sufficiente. Ma nel mio caso, l'input è garantito per essere completamente transalabile in ASCII. – Stephan

3

In primo luogo, stai solo tentando di analizzare una stringa letterale, oppure è tmp alcuni dati inseriti dall'utente?

Se questo sarà un valore letterale stringa (cioè una stringa hardcoded), può essere codificato utilizzando escape Unicode. Nel tuo caso, questo significa solo usando backslash singoli invece dei doppi backslash:

String result = "\u0068\u0065\u006c\u006c\u006f\u000a"; 

Se, tuttavia, è necessario utilizzare le regole all'analisi delle stringhe di Java per analizzare l'input dell'utente, un buon punto di partenza potrebbe essere il metodo di Apache Commons Lang StringEscapeUtils.unescapeJava() .

1

Sono sicuro che ci deve essere un modo migliore, ma usando solo il JDK:

public static String handleEscapes(final String s) 
{ 
    final java.util.Properties props = new java.util.Properties(); 
    props.setProperty("foo", s); 
    final java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream(); 
    try 
    { 
     props.store(baos, null); 
     final String tmp = baos.toString().replace("\\\\", "\\"); 
     props.load(new java.io.StringReader(tmp)); 
    } 
    catch(final java.io.IOException ioe) // shouldn't happen 
     { throw new RuntimeException(ioe); } 
    return props.getProperty("foo"); 
} 

utilizza java.util.Properties.load(java.io.Reader) per elaborare il backslash-escapes (dopo il primo utilizzo java.util.Properties.store(java.io.OutputStream, java.lang.String) al backslash-sfuggire nulla che possa causare problemi in un file di proprietà e quindi utilizzare replace("\\\\", "\\") per invertire l'inversione backslash dei backslash originali).

(Disclaimer:. Anche se ho provato tutti i casi mi veniva in mente, ci sono ancora alcuni che probabilmente ho fatto non pensare)