-1
votes

La sortie comprimée ZLIB peut-elle éviter d'utiliser certaines valeur d'octets?

Il semble que la sortie zlib.compress utilise toutes les valeurs d'octets possibles. Est-ce que cela est possible d'utiliser 255 de 256 valeurs d'octets (par exemple, évitez d'utiliser \ n )?

https://docs.python.org/3/library/zlib.html

Notez que je viens d'utiliser le manuel Python comme une référence, mais la question n'est pas spécifique à Python, mais toutes les autres langues ayant une bibliothèque ZLIB.


8 commentaires

ZLIB Complèvement n'utilise pas tous les "caractères" possibles qu'il utilise toutes les valeurs d'octets 8 bits possibles, c'est-à-dire 0-255. Il devrait être techniquement possible de mettre en œuvre votre propre schéma de compression similaire qui évite une valeur particulière, mais elle ne serait pas interchangeable avec une complat de zlib standard.


La bibliothèque zip de Python est implémentée en Python - la source est là, vous pouvez créer votre propre compression "user1424739Lib.


Vous pouvez utiliser une sorte de séquence d'échappement pour remplacer toutes les nouvelles lignes dans les données compressées - par exemple, remplacez les nouvelles lignes avec x1 , remplacez le x S avec x2 , inverser ces remplaçants à l'extrémité de réception avant de décompresser. (Il s'agit de la même idée de base que la façon dont les langages de programmation vous permettent d'inclure des marques de devis dans un littéral de chaîne cité, en leur précisant avec une barre oblique inverse.) Cela annule inévitablement une partie de votre compression - par un facteur 1/128 en moyenne, en moyenne. à un facteur de 2 si les données comprimées se produisent entièrement d'octets nécessitant une échappée (mais c'est très peu probable).


Je pense que vous pouvez convertir la sortie à 0-254, mais pas (facilement) pour pouvoir ignorer une valeur spécifique de la plage de 0 à 255. Quand cela sera acceptable?


@martineau OK. Cela semble être une solution de contournement raisonnable. Pourriez-vous fournir une implémentation de Python pour convertir le résultat de ZLIB.Compress et la convertir?


@martineau oui.


Bonne nouvelle, j'ai pu le faire et sans avoir à restreindre les valeurs à 0-254 - voir la réponse i postée.


Puis-je vous demander pourquoi vous voulez faire cela?


3 Réponses :


1
votes

Non, ce n'est pas possible. Outre les données comprimées elles-mêmes, il existe des structures de contrôle normalisées contenant des entiers. Ces entiers peuvent entraîner accidentellement un personnage de 8 bits se terminant dans la bytestream.

Votre seule chance serait de coder le zlib bytestream dans un autre format, par exemple. base64.


1 commentaires

base64 inviole l'objectif initial de compresser le flux. Existe-t-il un moyen de convertir un flux d'octets de 256 possibles à 255 types de types possible afin que je réserve '\ n' pour mon but?



0
votes

comme @ypnos dit , ce n'est pas possible dans Zlib même. Vous avez mentionné que le codage de base64 est trop inefficace, mais il est assez facile d'utiliser un caractère d'échappement pour encoder un personnage que vous souhaitez éviter (comme les lignes neuves).

Ce n'est pas le code le plus efficace du monde (et vous risquez de vouloir faire quelque chose comme trouver les octets les moins utilisés pour sauver un peu plus d'espace), mais c'est suffisamment lisible et démontre l'idée. Vous pouvez décoder / décoder de manière sans perte et le flux codé n'aura aucune nouvelle ligne de ligne. P>

from itertools import *

all(
    bytes(p) == decode(encode(bytes(p)))
        for c in combinations_with_replacement(b'ab\nc', r=6)
        for p in permutations(c)
)


4 commentaires

Est-ce que décodage () fonctionne correctement? Et si l'entrée d'origine contient AB ?


Oui. Vous obtenez AAB qui est décodé Retour à AB . Le code pourrait renvoyer une erreur si un A est suivi de quelque chose d'autre qu'un A ou B , mais il est libéral et renvoie \ n pour autre chose qu'un a suivant un a .


@Markadler La fonction Decode () a eu un bug que j'ai corrigé dans un édition (et AB était un cas où il échouerait). C'est un bon point que ce décodage () tentera de donner une réponse même pour des entrées non valides.


Ah ok. Je n'ai pas remarqué que le commentaire a précédé une modification.



1
votes

Le point de compression entier est de réduire le maximum de la taille que possible. Si zlib ou tout compresseur utilise uniquement 255 des valeurs de 256 octets, la taille de la sortie serait augmentée d'au moins 0,07%.

qui peut être parfaitement bien pour vous, de sorte que vous pouvez simplement poster la sortie compressée, ou des données du tout, pour supprimer une valeur d'octets particulière à la charge d'une expansion. L'approche la plus simple consisterait à remplacer cet octet lorsqu'il se produit avec une séquence d'échappement à deux octets. Vous devez également ensuite remplacer le préfixe d'évacuation avec une séquence d'échappement de deux octets différente. Cela élargirait les données en moyenne de 0,8%. C'est exactement ce que HANS fournit dans une autre réponse ici.

Si ce coût est trop élevé, vous pouvez faire quelque chose de plus sophistiqué, ce qui doit décoder un code de Huffman fixe qui code 255 symboles de probabilité égale. Pour vous décoder, codez que le code Huffman. L'entrée est une séquence de bits, non d'octets et la plupart du temps, vous devrez céder l'entrée avec quelques bits zéro pour encoder le dernier symbole. Le code Huffman transforme un symbole en sept bits et les 254 autres symboles en huit bits. Donc, aller dans l'autre sens, il élargira l'entrée d'un peu moins de 0,1%. Pour les messages courts, ce sera un peu plus, car souvent moins de sept bits à la fin seront codés dans un symbole.

implémentation en C: xxx


0 commentaires