2012-11-07 11 views
7

Ho un array String [] in Java e devo prima codificarlo/convertirlo in una stringa e quindi nel codice nascosto nuovamente all'array String []. Il fatto è che posso avere qualsiasi carattere in una stringa nell'array String [] quindi devo fare molta attenzione durante la codifica. E tutte le informazioni necessarie per decodificarlo devono essere nella stringa finale. Non riesco a restituire una stringa e altre informazioni in una variabile extra.Conversione della stringa di un array in stringa e ritorno in Java

mio algoritmo che ho messo a punto finora è quello di:

  1. Accoda tutte le stringhe uno accanto all'altro, per esempio come questo: String [] a = { "lala", "exe", "a"} in String b = "lalaexea"

  2. accoda alla fine della stringa le lunghezze di tutte le stringhe da String [], separata dal testo principale di $ segno e poi ogni lunghezza separati da una virgola, quindi:

b = "lalaexea $ 4,3,1"

Poi durante la conversione indietro, vorrei prima di leggere le lunghezze da dietro e poi sulla base di loro, i veri corde.

Ma forse c'è un modo più semplice?

Cheers!

+3

Trovo la tua idea buona! – sp00m

risposta

11

Se non vuoi spendere così tanto tempo con le operazioni di stringa è possibile utilizzare Java serializzazione + commons codecs come questo:

public void stringArrayTest() throws IOException, ClassNotFoundException, DecoderException { 
    String[] strs = new String[] {"test 1", "test 2", "test 3"}; 
    System.out.println(Arrays.toString(strs)); 

    // serialize 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    new ObjectOutputStream(out).writeObject(strs); 

    // your string 
    String yourString = new String(Hex.encodeHex(out.toByteArray())); 
    System.out.println(yourString); 

    // deserialize 
    ByteArrayInputStream in = new ByteArrayInputStream(Hex.decodeHex(yourString.toCharArray())); 
    System.out.println(Arrays.toString((String[]) new ObjectInputStream(in).readObject())); 
} 

Questo restituirà il seguente output :

[test 1, test 2, test 3] 
aced0005757200135b4c6a6176612e6c616e672e537472696e673badd256e7e91d7b47020000787000000003740006746573742031740006746573742032740006746573742033 
[test 1, test 2, test 3] 

Se si utilizza Maven, è possibile utilizzare il seguente dipendenza per comuni codec:

<dependency> 
    <groupId>commons-codec</groupId> 
    <artifactId>commons-codec</artifactId> 
    <version>1.2</version> 
</dependency> 

Come suggerito con base64 (due linee cambiano):

String yourString = new String(Base64.encodeBase64(out.toByteArray())); 
ByteArrayInputStream in = new ByteArrayInputStream(Base64.decodeBase64(yourString.getBytes())); 

In caso di Base64 stringa di risultato è più breve, per il codice esposto di seguito:

[test 1, test 2, test 3] 
rO0ABXVyABNbTGphdmEubGFuZy5TdHJpbmc7rdJW5+kde0cCAAB4cAAAAAN0AAZ0ZXN0IDF0AAZ0ZXN0IDJ0AAZ0ZXN0IDM= 
[test 1, test 2, test 3] 

quanto riguarda i tempi di ciascun approccio, eseguo 10^5 esecuzioni di ogni metodo e il risultato è stato il seguente:

  • Manipolazione stringa zione: 156 ms
  • Hex: 376 ms
  • Base64: 379 ms

codice utilizzato per le prove:

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.ObjectOutputStream; 
import java.util.StringTokenizer; 

import org.apache.commons.codec.DecoderException; 
import org.apache.commons.codec.binary.Base64; 
import org.apache.commons.codec.binary.Hex; 


public class StringArrayRepresentationTest { 

    public static void main(String[] args) throws IOException, ClassNotFoundException, DecoderException { 

     String[] strs = new String[] {"test 1", "test 2", "test 3"}; 


     long t = System.currentTimeMillis(); 
     for (int i =0; i < 100000;i++) { 
      stringManipulation(strs); 
     } 
     System.out.println("String manipulation: " + (System.currentTimeMillis() - t)); 


     t = System.currentTimeMillis(); 
     for (int i =0; i < 100000;i++) { 
      testHex(strs); 
     } 
     System.out.println("Hex: " + (System.currentTimeMillis() - t)); 


     t = System.currentTimeMillis(); 
     for (int i =0; i < 100000;i++) { 
      testBase64(strs); 
     } 
     System.out.println("Base64: " + (System.currentTimeMillis() - t)); 
    } 

    public static void stringManipulation(String[] strs) { 
     String result = serialize(strs); 
     unserialize(result); 
    } 

    private static String[] unserialize(String result) { 
     int sizesSplitPoint = result.toString().lastIndexOf('$'); 
     String sizes = result.substring(sizesSplitPoint+1); 
     StringTokenizer st = new StringTokenizer(sizes, ";"); 
     String[] resultArray = new String[st.countTokens()]; 

     int i = 0; 
     int lastPosition = 0; 
     while (st.hasMoreTokens()) { 
      String stringLengthStr = st.nextToken(); 
      int stringLength = Integer.parseInt(stringLengthStr); 
      resultArray[i++] = result.substring(lastPosition, lastPosition + stringLength); 
      lastPosition += stringLength; 
     } 
     return resultArray; 
    } 

    private static String serialize(String[] strs) { 
     StringBuilder sizes = new StringBuilder("$"); 
     StringBuilder result = new StringBuilder(); 

     for (String str : strs) { 
      if (sizes.length() != 1) { 
       sizes.append(';'); 
      } 
      sizes.append(str.length()); 
      result.append(str); 
     } 

     result.append(sizes.toString()); 
     return result.toString(); 
    } 

    public static void testBase64(String[] strs) throws IOException, ClassNotFoundException, DecoderException { 
     // serialize 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     new ObjectOutputStream(out).writeObject(strs); 

     // your string 
     String yourString = new String(Base64.encodeBase64(out.toByteArray())); 

     // deserialize 
     ByteArrayInputStream in = new ByteArrayInputStream(Base64.decodeBase64(yourString.getBytes())); 
    } 

    public static void testHex(String[] strs) throws IOException, ClassNotFoundException, DecoderException { 
     // serialize 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     new ObjectOutputStream(out).writeObject(strs); 

     // your string 
     String yourString = new String(Hex.encodeHex(out.toByteArray())); 

     // deserialize 
     ByteArrayInputStream in = new ByteArrayInputStream(Hex.decodeHex(yourString.toCharArray())); 
    } 

} 
+1

Questo è un metodo più sicuro di quelli proposti. L'overhead è più grande però, usando un'altra codifica di hex come base64 sarebbe una buona idea. – ARRG

+0

@ARRG: grazie per il tuo commento, ho appena commentato le modifiche necessarie per usare base64 –

+0

E come sono le prestazioni di queste due soluzioni (manipolazione delle stringhe vs proposta in questa risposta)? – Janek

-1

Basta usare un separatore noto (come @ o # per aggiungere le stringhe), quindi utilizzare yourString.split (yourSeparator) per ottenere un array da esso.

+0

non sicuro e tutto, poiché questa sequenza di caratteri può essere presente sulla stringa stessa –

+0

Bene, tendo ad essere d'accordo con te. Ma puoi comunque usare caratteri che sono proibiti da qualche altra parte nella tua applicazione, come ad esempio qualsiasi oggetto vietato nei database, ad esempio. Ovviamente @ e # erano esempi ... – dounyy

0

Vorrei utilizzare il simbolo tra le parole per utilizzare in seguito il metodo String#split per recuperare la stringa. Con sede a tuo esempio simbolo $, sarebbe

public String mergeStrings(String[] ss) { 
    StringBuilder sb = new StringBuilder(); 
    for(String s : ss) { 
     sb.append(s); 
     sb.append('$'); 
    } 
    return sb.toString(); 
} 

public String[] unmergeStrings(String s) { 
    return s.split("\\$"); 
} 

Nota che in questo esempio, aggiungo un doppio \ prima del simbolo $ perché il metodo String#split riceve un'espressione regolare come parametro, e il simbolo $ è una speciale personaggio in regex.

public String processData(String[] ss) { 
    String mergedString = mergeStrings(ss); 
    //process data... 
    //a little example... 
    for(int i = 0; i < mergedString.length(); i++) { 
     if (mergedString.charAt(i) == '$') { 
      System.out.println(); 
     } else { 
      System.out.print(mergedString.charAt(i)); 
     } 
    } 
    System.out.println(); 
    //unmerging the data again 
    String[] oldData = unmergeStrings(mergedString); 
} 

Per supportare qualsiasi carattere nel String[], sarebbe preferibile impostare non un singolo carattere come separatore ma invece un'altra String.I metodi si trasformerebbero in questo:

public static final String STRING_SEPARATOR = "@|$|@"; 
public static final String STRING_SEPARATOR_REGEX = "@\\|\\$\\|@"; 

public String mergeStrings(String[] ss) { 
    StringBuilder sb = new StringBuilder(); 
    for(String s : ss) { 
     sb.append(s); 
     sb.append(STRING_SEPARATOR); 
    } 
    return sb.toString(); 
} 

public String[] unmergeStrings(String s) { 
    return s.split(STRING_SEPARATOR_REGEX); 
} 
+0

l'OP spiegava che * può avere qualsiasi carattere in una stringa in String [] array *, quindi dovresti sfuggire al separatore scelto prima di * unire *, ad es. 's.replaceAll (" \\ $ "," \\\\\ $ ");'. – sp00m

+0

@ sp00m Preferirei il main dei dati invariati, invece proporre un nuovo pattern per separare ogni 'String' (ed è regex per dividerlo indietro). –

+0

ma non risolve il problema, tuttavia può succedere che questo modello si trovi in ​​una stringa in String []. Un'idea sarebbe quella di tracciare sempre lo schema ma poi c'è ancora una possibilità e non sembra essere una soluzione molto pulita. – Janek

0

Utilizzare un parser JSON come Jackson per serializzare/deserializzare altro tipo di oggetti così come integer/float ext alle stringhe e viceversa.

Problemi correlati