2012-11-07 131 views
7

我有一個數組的String []在Java中,並且必須首先編碼/將其轉換成一個字符串,然後進一步在代碼隱蔽它回到String []數組。問題是我可以在String []數組中有任何字符,所以在編碼時我必須非常小心。並且解碼它所需的所有信息必須在最後一個字符串中。我不能在一個額外的變量中返回一個字符串和其他信息。轉換數組字符串字符串和背面中的Java

我的算法到目前爲止我設計是:

  1. 追加所有字符串彼此相鄰,例如是這樣的: 字符串[] A = {「拉拉」,「執行」, 「一」} 成 串b =「lalaexea」

  2. 追加在字符串的結束時從所有的字符串的長度字符串[],從由$符號的主文本,然後通過分離的每個長度分離一個逗號,如下:

B =「lalaexea $ 4,3,1」

然後將其轉換回來的時候,我會先看從後面,然後長度基於這些,真正的字符串。

但也許有一個更簡單的方法?

乾杯!

+3

我覺得你的主意很好! – sp00m

回答

11

如果你不想用字符串操作,您可以使用Java序列化+ commons codecs這樣花這麼多時間:

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

這將返回以下輸出:

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

如果您正在使用Maven,你可以使用下面的依賴於公共編解碼器:

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

與BASE64建議(兩行改變):

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

在Base64的情況下的結果字符串較短,爲下面的代碼暴露:

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

關於次,每次方法,我對每種方法執行10^5次執行,結果如下:

  • String manipula和灰:156毫秒
  • 十六進制:376毫秒
  • 的Base64:379毫秒

代碼用於測試:

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

這比建議的方法更安全。雖然開銷較大,但使用另一種比hex等十六進制編碼將是一個好主意。 – ARRG

+0

@ARRG:感謝您的評論,我剛剛評論了使用base64所需的更改 –

+0

這兩個解決方案的性能如何(字符串操作vs在此答案中提出)如何? – Janek

-1

只需使用已知的分隔符(例如@#來追加字符串),然後使用yourString.split(yourSeparator)從中獲取數組。

+0

不安全等等,因爲這個字符序列可以存在於字符串本身 –

+0

嗯,我傾向於同意你的觀點。但是你仍然可以使用應用程序中其他地方禁止使用的字符,例如數據庫中禁止使用的任何字符。當然@和#是例子...... – dounyy

0

我會用單詞之間的符號後使用String#split方法來獲取字符串返回。根據您的$符號例子,這將是

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

注意,在這個例子中,我添加了一個雙\$符號,因爲String#split方法接收一個正則表達式作爲參數,並且$符號是一個特殊的正則表達式中的字符。

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

爲了支持你的String[]任何字符,這將是更好的設置不是一個單一的字符作爲分隔符,而是另一個String。該方法會變成這樣:

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 [] array *中的字符串中包含任何字符,所以你應該在*加入*之前退出所選擇的分隔符,例如。 's.replaceAll(「\\ $」,「\\\\\ $」);'。 – sp00m

+0

@ sp00m我寧願主要保持不變的數據,而是提出一種新的模式來分隔每個「字符串」(並且它是正則表達式來分割它)。 –

+0

但它不能解決問題,但仍然可能發生這種模式將在String []中的字符串之一。一個想法是總是繪製模式,但仍然有可能,它似乎不是一個非常乾淨的解決方案。 – Janek

0

使用的JSON解析器等傑克遜序列化/反序列化其他類型的對象以及像整數/浮動ext到字符串和後面。