10

Javaに配列String[]があり、最初にそれを文字列にエンコード/変換してから、コード内でさらにString[]配列に変換する必要があります。重要なのは、String []配列の文字列に任意の文字を含めることができるため、エンコードするときは十分に注意する必要があるということです。そして、それをデコードするために必要なすべての情報は、最終的な文字列に含まれている必要があります。文字列やその他の情報を追加の変数で返すことはできません。

これまでに考案した私のアルゴリズムは次のとおりです。

  1. たとえば、次のように、すべての文字列を並べて追加します。String [] a = {"lala"、 "exe"、 "a"} into String b = "lalaexea"

  2. 文字列の最後に、String []のすべての文字列の長さを追加し、本文から$記号で区切ってから、各長さをコンマで区切ってください。

b = "lalaexea $ 4,3,1"

それからそれを元に戻すとき、私は最初に後ろから長さを読み、次にそれらに基づいて実際の文字列を読みます。

しかし、もっと簡単な方法があるのでしょうか?

乾杯!

4

4 に答える 4

13

文字列操作にあまり時間をかけたくない場合は、次のようなJavaシリアル化とコモンズコーデックを使用できます。

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で提案されているように(2行変更):

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回実行した結果、次のようになりました。

  • 文字列操作:156ミリ秒
  • 16進数: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()));
    }

}
于 2012-11-07T14:39:39.547 に答える
1

JacksonのようなJsonパーサーを使用して、他のタイプのオブジェクトをシリアル化/逆シリアル化し、integer /floatsextを文字列に戻したり戻したりします。

于 2013-11-08T14:40:37.223 に答える
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("\\$");
}

この例では、メソッドがパラメーターとして正規表現を受け取り、シンボルが正規表現の特殊文字であるため、シンボルの\前にdoubleを追加していることに注意してください。$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[]は、1つの文字を区切り文字として設定するのではなく、別の文字を設定することをお勧めします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);
}
于 2012-11-07T14:19:41.283 に答える
-1

既知のセパレーター(@または#文字列を追加するなど)を使用してから、yourString.split(yourSeparator)を使用して配列を取得します。

于 2012-11-07T14:19:01.430 に答える