lzw_compression.sf 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #!/usr/bin/ruby
  2. # Implementation of the LZW compression algorithm.
  3. # See also:
  4. # https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch
  5. # Compress a string to a list of output symbols.
  6. func compress(String uncompressed) -> Array {
  7. # Build the dictionary.
  8. var dict_size = 256;
  9. var dictionary = Hash.new;
  10. 0 .. dict_size-1 -> each { |i|
  11. dictionary{i.chr} = i.chr;
  12. };
  13. var w = '';
  14. var result = [];
  15. uncompressed.each { |c|
  16. var wc = w+c;
  17. if (dictionary.has_key(wc)) {
  18. w = wc;
  19. } else {
  20. result.append(dictionary{w});
  21. # Add wc to the dictionary.
  22. dictionary{wc} = dict_size;
  23. dict_size++;
  24. w = c;
  25. }
  26. };
  27. # Output the code for w.
  28. if (w != '') {
  29. result.append(dictionary{w});
  30. };
  31. return result;
  32. };
  33. # Decompress a list of output ks to a string.
  34. func decompress(Array compressed) -> String {
  35. # Build the dictionary.
  36. var dict_size = 256;
  37. var dictionary = Hash.new;
  38. 0 .. dict_size-1 -> each { |i|
  39. dictionary{i.chr} = i.chr;
  40. };
  41. var w = compressed.shift;
  42. var result = w;
  43. compressed.each { |k|
  44. var entry;
  45. if (dictionary.has_key(k)) {
  46. entry = dictionary{k};
  47. } elsif (k == dict_size) {
  48. entry = w+w.substr(0,1);
  49. } else {
  50. die "Bad compressed k: #{k}";
  51. };
  52. result += entry;
  53. # Add w+entry[0] to the dictionary.
  54. dictionary{dict_size} = w+entry.substr(0,1);
  55. dict_size++;
  56. w = entry;
  57. };
  58. return result;
  59. };
  60. # How to use:
  61. var compressed = compress('TOBEORNOTTOBEORTOBEORNOT');
  62. say compressed.join(' ');
  63. var decompressed = decompress(compressed);
  64. say decompressed;