2012-11-07 17 views
7

Java'da bir dizi String [] var ve önce onu bir String'e kodlamalı/dönüştürmeli ve daha sonra kodda daha sonra String [] dizisine geri dönüştürmeliyiz. Bir şey String [] dizisinde bir dizede herhangi bir karaktere sahip olabilmem, bu yüzden kodlarken çok dikkatli olmalıyım. Ve kodunu çözmek için gerekli olan tüm bilgiler son dizede olmalıdır. Bir string ve başka bir bilgiyi fazladan bir değişkene iade edemem. Yan yana, böyle örneğinDizgeyi dizgeye ve arkaya dönüştürme

  1. Ekleme tüm dizeleri: Şimdiye kadar taktığı

    Benim algoritma etmektir String [] a = { "lala", "exe", dizesinin sonunda Yaylı b = "lalaexea"

  2. ekleme içine "a"} tüm şeritlerinin uzunluğu string [], $ işareti ana metin ve daha sonra ayrılmış her uzunluğundan aynlır Bir virgül, yani:

b = "lalaexea $ 4,3,1" geri dönüştürürken

Sonra ben ilk onlarla gerçek dizeleri dayalı arkasında ve o andan itibaren uzunlukları okurdu.

Belki daha kolay bir yol var mı?

Şerefe!

+3

Fikrinizi güzel buluyorum! – sp00m

cevap

11

Eğer böyle java seri + commons codecs kullanabilirsiniz dize operasyonları ile çok fazla zaman harcamak istemiyorsan : Eğer maven kullanıyorsanız

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

, sen commons codec bileşeni için aşağıdaki bağımlılık kullanabilirsiniz:

base64 ile beyan edildiği gibi
<dependency> 
    <groupId>commons-codec</groupId> 
    <artifactId>commons-codec</artifactId> 
    <version>1.2</version> 
</dependency> 

(iki satır değiştirme):

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

Base64 durumunda kod aşağıda maruz için sonuç dizesi, kısadır:

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

her zaman İlişkin yaklaşım, her yöntemin 10^5 yürütme gerçekleştirir ve sonuç aşağıdaki gibi oldu:

  • Dize işleci siyon: 156 ms
  • Hex: 376 ms
  • Base64: 379 ms
  • Kod testi için kullanılan

:

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

Bu, önerilenlerden daha güvenli bir yöntemdir. Tepegöz daha büyüktür, ancak base64 gibi hex'ten başka bir kodlama kullanmak iyi bir fikir olur. – ARRG

+0

@ARRG: Yorumunuz için teşekkürler, sadece base64 kullanabilmek için gerekli değişiklikleri yorumladım –

+0

Ve bu iki çözümün performansı nasıl (bu cevapta önerilen tel manipülasyonu vs)? – Janek

-1

Sadece bilinen bir ayırıcıyı kullanın (örneğin, dizelerinizi eklemek için @ veya # gibi), daha sonra bir dizi almak içinString.split'i (kendi Süzgeci) kullanın.

+0

güvenli değildir, çünkü bu char dizisi dizenin kendisinde mevcut olabileceğinden –

+0

Eh, sizinle aynı fikirde olma eğilimindeyim. Ancak, uygulamanızda başka yerlerde yasaklanmış olan chars'ları kullanabilirsiniz. Örneğin, veritabanlarında herhangi bir yasak gibi. Elbette @ ve # örnekler ... – dounyy

0

Dize geri almak için daha sonra String#split yöntemini kullanmak için sözcükler arasındaki sembolü kullanırdım. senin $ sembol örnekte dayanarak, bu örnekte, String#split yöntem parametresi olarak normal bir ifade alır çünkü çifte \ önce $ sembol ekleyin ve $ sembol özel olduğunu

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("\\$"); 
} 

Not olurdu regex karakter. senin String[] herhangi bir karakter desteklemek amacıyla

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

, değil ayırıcı ancak bunun yerine başka String gibi tek bir karakteri belirlemek için daha iyi olurdu.yöntemler bu dönüşeceğini:

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

Bu aşağıdaki çıktıyı döndürür:

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

, OP, String [] dizisi * içindeki bir dizede herhangi bir karaktere sahip olabileceğini açıklamıştır, böylece * birleştirmeden * önce seçilen ayırıcıdan çıkmalısınız, ör. s.replaceAll ("\\ $", "\\\\\\ $"); '. – sp00m

+0

@ sp00m Verileri değişmeden değiştirmeyi tercih ederim, bunun yerine her bir String’i ayırmak için yeni bir şablon öneririm (ve bunu geri almak için regex). –

+0

ancak sorunu çözmüyor, yine de bu desenin String [] 'deki dizgilerden birinde olması mümkündür. Bir fikir her zaman kalıbı çizmek olurdu, ama yine de bir olasılık var ve çok temiz bir çözüm gibi görünmüyor. – Janek

0

Kullanım Jackson gibi bir Json ayrıştırıcı getirilmeye/nesnelerin başka türde serisini tamsayı/dizgiler gibi dizgilerle ve geriye doğru.