Преобразование массива в строку и обратно в Java
У меня есть строка массива[] в Java и должна сначала закодировать / преобразовать ее в строку, а затем далее в коде скрыть ее обратно в массив String []. Дело в том, что я могу иметь любой символ в строке в массиве String [], поэтому я должен быть очень осторожным при кодировании. И вся информация, необходимая для ее декодирования, должна быть в последней строке. Я не могу вернуть строку и некоторую другую информацию в дополнительной переменной.
мой алгоритм, который я разработал до сих пор кому:
добавить все строки рядом друг с другом, например, как этот: String[] a = {"lala", "exe", " a"} в Строка b = "lalaexea"
добавьте в конце строки длины всех строк из String [], отделенные от основного текста знаком$, а затем каждую длину, разделенную запятой, так:
b = "lalaexea$4,3,1"
затем при преобразовании его обратно, я бы сначала прочитал длины из и затем на их основе реальные строки.
но может есть более простой способ?
Ура!
4 ответов
если вы не хотите тратить так много времени на строковые операции, вы можете использовать сериализацию 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, вы можете использовать следующую зависимость для кодека commons:
<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 выполнения каждого метода, и результат был следующим:
- строка манипуляции: 156 ms
- Hex: 376 ms
- Base64: 379 ms
код, используемый для теста:
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()));
}
}
Я бы использовал символ между словами, чтобы позже использовать 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[]
, было бы лучше установите не один символ в качестве разделителя, а вместо другого 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);
}
используйте парсер Json, такой как Jackson, для сериализации/десериализации других типов объектов, а также integer/floats ext в строки и обратно.
просто используйте известный разделитель (например,@
или #
для добавления строк), затем используйте yourString.split (yourSeparator), чтобы получить массив из него.