web-dev-qa-db-fra.com

Compression de chaînes en JavaScript

Je recherche une fonction JavaScript qui, étant donné une chaîne, renvoie une chaîne compressée (plus courte).

Je suis en train de développer une Chrome qui enregistre les longues chaînes (HTML) dans une base de données locale. À des fins de test, j'ai essayé de compresser le fichier stockant la base de données, et il a diminué d'un facteur cinq , donc j'ai pensé que cela aiderait à garder la base de données plus petite si je compressais les choses qu'elle stocke.

J'ai trouvé une implémentation de LZSS en JavaScript ici: http://code.google.com/p/u-lzss/ ("U-LZSS").

Cela semblait fonctionner quand je l'ai testé "à la main" avec de courts exemples de chaînes (décoder === encoder), et c'est assez rapide aussi, dans Chrome. Mais quand on donne de grosses cordes (100 ko), cela semble brouiller/mélanger la dernière moitié de la corde.

Est-il possible que U-LZSS s'attende à des chaînes courtes et ne puisse pas gérer des chaînes plus grandes? Et serait-il possible d'ajuster certains paramètres afin de déplacer cette limite supérieure?

35
Bambax

À la suggestion de Piskvor, j'ai testé le code trouvé dans une réponse à cette question: implémentation JavaScript de Gzip (réponse la plus votée: implémentation LZW) et constaté que:

  1. ça marche
  2. il réduit la taille de la base de données d'un facteur deux

... qui est moins de 5 mais mieux que rien! J'ai donc utilisé ça.

(J'aurais aimé pouvoir accepter une réponse de Piskvor mais ce n'était qu'un commentaire).

5
Bambax

Je viens de publier une petite LZW implémentation spécialement conçue à cet effet car aucune des implémentations existantes ne répondait à mes besoins.

C'est ce que j'utilise à l'avenir, et je vais probablement essayer d'améliorer la bibliothèque à un moment donné.

30
pieroxy

Voici les fonctions d'encodage (276 octets, fonction en) et de décodage (191 octets, fonction de) que j'ai modifiées à partir de LZW dans une démo pleinement fonctionnelle. Il n'y a pas de routine plus petite ou plus rapide disponible sur Internet que ce que je vous donne ici.

function en(c){var x='charCodeAt',b,e={},f=c.split(""),d=[],a=f[0],g=256;for(b=1;b<f.length;b++)c=f[b],null!=e[a+c]?a+=c:(d.Push(1<a.length?e[a]:a[x](0)),e[a+c]=g,g++,a=c);d.Push(1<a.length?e[a]:a[x](0));for(b=0;b<d.length;b++)d[b]=String.fromCharCode(d[b]);return d.join("")}

function de(b){var a,e={},d=b.split(""),c=f=d[0],g=[c],h=o=256;for(b=1;b<d.length;b++)a=d[b].charCodeAt(0),a=h>a?d[b]:e[a]?e[a]:f+c,g.Push(a),c=a.charAt(0),e[o]=f+c,o++,f=a;return g.join("")}

var compressed=en("http://www.ScriptCompress.com - Simple Packer/Minify/Compress JavaScript Minify, Fixify & Prettify 75 JS Obfuscators In 1 App 25 JS Compressors (Gzip, Bzip, LZMA, etc) PHP, HTML & JS Packers In 1 App PHP Source Code Packers Text Packer HTML Packer or v2 or v3 or LZW Twitter Compress or More Words DNA & Base64 Packer (freq tool) or v2 JS JavaScript Code Golfer Encode Between Quotes Decode Almost Anything Password Protect Scripts HTML Minifier v2 or Encoder or Escaper CSS Minifier or Compressor v2 SVG Image Shrinker HTML To: SVG or SVGZ (Gzipped) HTML To: PNG or v2 2015 JS Packer v2 v3 Embedded File Generator Extreme Packer or version 2 Our Blog DemoScene JS Packer Basic JS Packer or New Version Asciify JavaScript Escape JavaScript Characters UnPacker Packed JS JavaScript Minify/Uglify Text Splitter/Chunker Twitter, Use More Characters Base64 Drag 'n Drop Redirect URL DataURI Get Words Repeated LZMA Archiver Zip Read/Extract/Make BEAUTIFIER & CODE FIXER WHAK-A-SCRIPT JAVASCRIPT MANGLER 30 STRING ENCODERS CONVERTERS, ENCRYPTION & ENCODERS 43 Byte 1px GIF Generator Steganography PNG Generator WEB APPS VIA DATAURL OLD VERSION OF WHAK PAKr Fun Text Encrypt Our Google");
var decompressed=de(compressed);

document.writeln('<hr>'+compressed+'<hr><h1>'+compressed.length+' characters versus original '+decompressed.length+' characters.</h1><hr>'+decompressed+'<hr>');
7
Dave Brown

Pour moi, il ne semble pas raisonnable de compresser une chaîne en utilisant UTF-8 comme destination ... On dirait juste chercher des ennuis. Je pense qu'il serait préférable de perdre une certaine compression et d'utiliser le simple 7 bits ASCII comme destination.

Dans un jouet Démo JavaScript de 4 Ko J'ai écrit pour le plaisir J'ai utilisé un encodage pour le résultat de la compression qui stocke quatre octets binaires dans cinq caractères choisis dans un sous-ensemble de ASCII de 85 caractères propres à être incorporés dans une chaîne JavaScript (85 ^ 5 est légèrement supérieur à 8 ^ 4, mais tient toujours dans la précision des entiers JavaScript). Cela rend les données compressées sûres, par exemple pour JSON sans besoin de s'échapper.

5
6502

Je pense que vous devriez également regarder lz-string c'est rapide un compresse assez bien et a quelques avantages qu'ils énumèrent sur leur page:

Qu'en est-il des autres bibliothèques?

  • certaines implémentations LZW qui vous rendent des tableaux de nombres (terriblement inefficaces à stocker car les jetons prennent 64 bits) et ne prennent en charge aucun caractère supérieur à 255.
  • d'autres implémentations LZW qui vous rendent une chaîne (moins terriblement inefficace à stocker mais quand même, tous les jetons prennent 16 bits) et ne prennent en charge aucun caractère supérieur à 255.
  • une implémentation LZMA qui est asynchrone et très lente - mais bon, c'est LZMA, pas l'implémentation qui est lente.
  • une implémentation GZip pas vraiment destinée aux navigateurs mais destinée à node.js, qui pesait 70kb (avec deflate.js et crc32.js dont elle dépend).

Les raisons pour lesquelles l'auteur a créé la chaîne lz:

  • En travaillant sur mobile, j'avais besoin de quelque chose de rapide.
  • En travaillant avec des chaînes recueillies à l'extérieur de mon site Web, j'avais besoin de quelque chose qui puisse prendre n'importe quel type de chaîne en entrée, y compris tous les caractères UTF supérieurs à 255.
  • La bibliothèque ne prenant pas 70 Ko était un avantage certain. Quelque chose qui produit des chaînes aussi compactes que possible à stocker dans localStorage. Donc, aucune des bibliothèques que j'ai pu trouver en ligne ne répondait bien à mes besoins.

Il y a des implémentations de cette lib dans d'autres langages, je suis actuellement en train de chercher dans l'implémentation python, mais la décompression semble avoir des problèmes pour le moment, mais si vous vous en tenez à JS seulement ça a l'air vraiment bien tome.

1
Nils Ziehn

Essayez d'expérimenter avec des fichiers texte avant d'implémenter quoi que ce soit, car je pense que ce qui suit ne tient pas nécessairement:

j'ai donc pensé que cela aiderait à garder la base de données plus petite si je compressais les choses qu'elle stocke.

En effet, les algorithmes de compression sans perte sont assez bons avec des motifs répétitifs (par exemple, les espaces blancs).

1
cherouvim

Il semble qu'il existe une proposition d'API de compression/décompression: https://github.com/wicg/compression/blob/master/explainer.md .

Et il est implémenté en Chrome 80 (en ce moment en version bêta) selon un article de blog à https://blog.chromium.org/2019/12/chrome-80- content-indexing-es-modules.html .

Je ne suis pas sûr de faire une bonne conversion entre les flux et les chaînes, mais voici mon essai d'utiliser la nouvelle API:

    var encoding = 'deflate'; // or 'gzip'

    function compress(text) {
      var byteArray = new TextEncoder().encode(text);
      var cs = new CompressionStream(encoding);
      var writer = cs.writable.getWriter();
      writer.write(byteArray);
      writer.close();
      return new Response(cs.readable).arrayBuffer();
    }

    function decompress(byteArray) {
      var cs = new DecompressionStream(encoding);
      var writer = cs.writable.getWriter();
      writer.write(byteArray);
      writer.close();
      return new Response(cs.readable).arrayBuffer().then(function (arrayBuffer) {
        return new TextDecoder().decode(arrayBuffer);
      });
    }
    
    var test = "http://www.ScriptCompress.com - Simple Packer/Minify/Compress JavaScript Minify, Fixify & Prettify 75 JS Obfuscators In 1 App 25 JS Compressors (Gzip, Bzip, LZMA, etc) PHP, HTML & JS Packers In 1 App PHP Source Code Packers Text Packer HTML Packer or v2 or v3 or LZW Twitter Compress or More Words DNA & Base64 Packer (freq tool) or v2 JS JavaScript Code Golfer Encode Between Quotes Decode Almost Anything Password Protect Scripts HTML Minifier v2 or Encoder or Escaper CSS Minifier or Compressor v2 SVG Image Shrinker HTML To: SVG or SVGZ (Gzipped) HTML To: PNG or v2 2015 JS Packer v2 v3 Embedded File Generator Extreme Packer or version 2 Our Blog DemoScene JS Packer Basic JS Packer or New Version Asciify JavaScript Escape JavaScript Characters UnPacker Packed JS JavaScript Minify/Uglify Text Splitter/Chunker Twitter, Use More Characters Base64 Drag 'n Drop Redirect URL DataURI Get Words Repeated LZMA Archiver Zip Read/Extract/Make BEAUTIFIER & CODE FIXER WHAK-A-SCRIPT JAVASCRIPT MANGLER 30 STRING ENCODERS CONVERTERS, ENCRYPTION & ENCODERS 43 Byte 1px GIF Generator Steganography PNG Generator WEB APPS VIA DATAURL OLD VERSION OF WHAK PAKr Fun Text Encrypt Our Google";

    console.time('compress');
    compress(test).then(function (x) {
      console.timeEnd('compress');
      console.log('compressed length', x.byteLength);
      console.time('decompress');
      decompress(x).then(function (y) {
        console.timeEnd('decompress');
        console.log('decompressed length', y.length);
        console.assert(test === y);
      });
    });
0
4esn0k