2013-07-26 7 views
19

Ho un'applicazione Web (ruby on rails) che invia un po 'di YAML come valore di un campo di input nascosto.Comprimere una stringa grande in rubino

Ora voglio ridurre la dimensione del testo inviato al browser. Qual è la forma più efficiente di compressione lossless che verrebbe inviata su dati minimi? Sto bene per sostenere costi aggiuntivi di compressione e decompressione sul lato server.

risposta

47

È possibile utilizzare l'implementazione zlib nel nucleo rosso rubino al/i dati de-flate:

require "zlib" 
data = "some long yaml string" * 100 
compressed_data = Zlib::Deflate.deflate(data) 
#=> "x\x9C+\xCE\xCFMU\xC8\xC9\xCFKW\xA8L\xCC\xCDQ(.)\xCA\xCCK/\x1E\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15\x1C\x15D\x15\x04\x00\xB3G%\xA6" 

Si dovrebbe base64 codificare i dati compressi per renderlo stampabile:

require 'base64' 
encoded_data = Base64.encode64 compressed_data 
#=> "eJwrzs9NVcjJz0tXqEzMzVEoLinKzEsvHhUcFRwVHBUcFRwVHBUcFUQVBACz\nRyWm\n" 

tardi , sul lato client, è possibile utilizzare pako (una porta zlib su javascript) per recuperare i dati. This answer probabilmente ti aiuta nell'implementazione della parte JS.

Per dare un'idea su quanto sia efficace questo è, qui ci sono le dimensioni dell'esempio stringhe:

data.size   # 2100 
compressed_data.size # 48 
encoded_data.size # 66 

Stessa cosa vale viceversa durante la compressione sul client e gonfiando sul server.

Zlib::Inflate.inflate(Base64.decode64(encoded_data)) 
#=> "some long yaml stringsome long yaml str ... (shortened, as the string is long :) 

responsabilità:

  • Lo zlib rubino implementazione dovrebbe essere compatibile con l'attuazione Pako. Ma non l'ho provato
  • I numeri relativi alle dimensioni delle corde sono un po 'ingannevoli. Zlib è davvero efficace qui, perché la stringa ripete molto. I dati della vita reale di solito non si ripetono più.
+2

Ciò nonostante, ho scartato questo accidente qualche giorno fa perché non ricordo di averlo fatto. Se per favore, fai una modifica in modo da poter ritirare il mio accidentale voto negativo :( – Krule

+2

@Krule grazie per essere gentile. Prima non ero sicuro di trovare un aggiornamento utile, ma poi sono inciampato su pako che (sembra) è una libreria zlib molto migliore di zlib, quindi grazie per il promemoria di guardare di nuovo la mia risposta, potrei effettivamente migliorarla :) – tessi

+4

Si noti che l'output di 'Zlib :: Deflate.deflate' non è compatibile con il formato che l'utilità della riga di comando 'gzip' genera e non sarà accettata da' gunzip', che si aspetta alcuni dati di intestazione prima del contenuto compresso. Se vuoi leggere l'output usando 'gunzip', sarà utile il seguente codice:' Zlib :: Deflate.new (nil, 31) .deflate (data, Zlib :: FINISH) ' – Guss