Как я могу значительно уменьшить размер кодируемой строки (хэш), сохраняя ее обратимой?JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Как я могу значительно уменьшить размер кодируемой строки (хэш), сохраняя ее обратимой?

Сообщение Anonymous »

Я работаю над приложением Java (JDK 21), где мне нужно передавать очень большую строку (около 20 000 символов). Эта строка представляет собой кодируемую структуру (например, хэш или сериализованные данные), и мне нужно: < /p>
Кодированный результат, который будет как можно более коротким, в идеале менее 4000 символов. < /P>
Процесс, который должен быть полностью обратный (я должен восстановить исходную строку). Кэш. < /p>
Чистое решение только для Java, нет зависимости от внешних инструментов или служб. BASE64URL-кодированный дефтат. < /P>
Таким образом, мой вопрос: < /p>
Есть ли более эффективный способ-алгоритмический, пользовательский кодирование или иным образом-чтобы уменьшить размер большой струны, в то время как она обратима и внедрена в простой Java? ценится! < /p>
public class EncryptionUtil {

private static final String AES = "AES/ECB/PKCS5Padding";
private static final String SECRET = "secret";
private final SecretKey secretKey;
private final RefinementEncryptionConfig encryptionConfig;

public FilterEncryptionUtil(RefinementEncryptionConfig encryptionConfig) {
this.encryptionConfig = encryptionConfig;
this.secretKey = new SecretKeySpec(SECRET.getBytes(StandardCharsets.UTF_8), "AES");
}

public String generateEncryptedUrl(List refinements) {
String compactString = generateCompactRefinementString(refinements);
return encryptCompactString(compactString);
}

public String encryptCompactString(String compactString) {
try {
Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encrypted = cipher.doFinal(compactString.getBytes(StandardCharsets.UTF_8));
return Base64.getUrlEncoder().withoutPadding().encodeToString(encrypted);
} catch (Exception e) {
throw new RuntimeException("Encryption failed", e);
}
}

private String generateCompactRefinementString(List refinements) {
Map navigationAliases = encryptionConfig.getEncryptIdentifiers();

StringBuilder buffer = new StringBuilder();
Map valueRefinements = new LinkedHashMap();
List rangeRefinements = new ArrayList();

for (Refinement r : refinements) {
String alias = navigationAliases.getOrDefault(r.getNavigationName(), r.getNavigationName());

if ("Range".equalsIgnoreCase(r.getType())) {
String rangeStr = alias + ":R:" + r.getLow() + "-" + r.getHigh();
rangeRefinements.add(rangeStr);
} else {
valueRefinements.computeIfAbsent(alias, k -> new ArrayList()).add(r.getValue());
}
}

if (!rangeRefinements.isEmpty()) {
buffer.append(String.join("#", rangeRefinements));
}

for (Map.Entry entry : valueRefinements.entrySet()) {
if (!buffer.isEmpty()) buffer.append("#");
String part = entry.getKey() + ":V:" + String.join("|", entry.getValue());
buffer.append(part);
}

return buffer.toString();
}

public List decodeEncryptedUrl(String encryptedBase64) {
try {
byte[] decoded = Base64.getUrlDecoder().decode(encryptedBase64);

Cipher cipher = Cipher.getInstance(AES);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedBytes = cipher.doFinal(decoded);
String compactString = new String(decryptedBytes, StandardCharsets.UTF_8);

return parseCompactRefinementString(compactString);
} catch (Exception e) {
throw new RuntimeException("Decryption failed", e);
}
}

private List parseCompactRefinementString(String compactString) {
List refinements = new ArrayList();
Map aliasToNav = encryptionConfig.getDecryptIdentifiers();

String[] parts = compactString.split("#");
for (String part : parts) {
String[] section = part.split(":");
if (section.length < 3) continue;

String alias = section[0];
String type = section[1];
String data = section[2];
String navName = aliasToNav.getOrDefault(alias, alias);

if ("R".equals(type)) {
String[] range = data.split("-");
if (range.length == 2) {
Refinement r = new Refinement();
r.setType("Range");
r.setNavigationName(navName);
r.setLow(range[0]);
r.setHigh(range[1]);
refinements.add(r);
}
} else if ("V".equals(type)) {
String[] values = data.split("\\|");
for (String value : values) {
Refinement r = new Refinement();
r.setType("Value");
r.setNavigationName(navName);
r.setValue(value);
refinements.add(r);
}
}
}

return refinements;
}

}
< /code>
Дополнительный контекст: < /p>
Чтобы прояснить некоторые ограничения: < /p>
Я не могу использовать запрос поста - кодируемые данные должны передаваться как параметр URL в запросе Get. Ограничения). < /p>
Я кодирую большой список целых чисел (например, [6957109, 11370445, ...], потенциально до 20 000 уникальных значений). < /p>
Эти цифры не повторяются и должны сохранены, и это должно быть в соответствии с Decode. Весь процесс, автономный в Java, без внешних служб, без базы данных (например, Mongo) и без временного кэша (например, Redis). < /p>
Мне не разрешено изменять архитектурное решение, включая картирование данных с UUID или внешним поиском. Кодирование. < /p>
Я попробовал Deflate + base64 (url-safe), но с 20 000 чисел, конечная строка по-прежнему оказывается слишком большой. Я ищу такие идеи, как: < /p>
Лучшие стратегии сжатия для списков целых чисел в Java. < /P>
Кодирование пользовательского числа (например, кодирование дельта, кодирование переменной длины). Методы только для Java были бы невероятно полезны. Спасибо! < /P>
public static byte[] compress(List numberStrings) throws IOException {
if (numberStrings == null || numberStrings.isEmpty()) return new byte[0];

// Convert strings to longs and sort
List numbers = numberStrings.stream()
.map(Long::parseLong)
.sorted()
.toList();

// Delta encoding with variable-length bytes
List deltas = new ArrayList();
long prev = numbers.get(0);
deltas.add((byte) (prev & 0xFF)); // Store first number's least significant byte

for (int i = 1; i < numbers.size(); i++) {
long delta = numbers.get(i) - prev;
prev = numbers.get(i);
while (delta > 0) {
byte b = (byte) (delta & 0x7F);
delta >>>= 7; // Use unsigned right shift
if (delta > 0) b |= 0x80;
deltas.add(b);
}
}

// Deflate compression
Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, true);
deflater.setInput(toByteArray(deltas));
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
deflater.finish();
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
baos.write(buffer, 0, count);
}
return baos.toByteArray();
} finally {
deflater.end();
}
}

private static byte[] toByteArray(List bytes) {
byte[] result = new byte[bytes.size()];
for (int i = 0; i < bytes.size(); i++) {
result = bytes.get(i);
}
return result;
}

public static List decompress(byte[] compressed) {
if (compressed == null || compressed.length == 0) return new ArrayList();

// Inflate decompression
Inflater inflater = new Inflater(true);
inflater.setInput(compressed);
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
while (!inflater.finished()) {
int count = inflater.inflate(buffer);
baos.write(buffer, 0, count);
}
return decodeDeltas(baos.toByteArray());
} catch (Exception e) {
e.printStackTrace();
return new ArrayList();
} finally {
inflater.end();
}
}

private static List decodeDeltas(byte[] decompressedBytes) {
List numbers = new ArrayList();
int value = decompressedBytes[0] & 0xFF;
numbers.add(value);

for (int i = 1; i < decompressedBytes.length; ) {
int delta = 0;
int shift = 0;
while (i < decompressedBytes.length && (decompressedBytes & 0x80) != 0) {
delta |= (decompressedBytes & 0x7F)

Подробнее здесь: https://stackoverflow.com/questions/796 ... ile-keepin
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «JAVA»