RLE(ランレンングス)法はわかりやすいなあ。

1B 1B 1B 1B 2C 2C 33 98 98 98

というデータを

04 1B 02 2C 01 33 03 98

というような、データとそれが連続して出た回数で書き記すような方法をランレングス法(RLE)と呼びます。

でも少し考えるとわかることがありまして。連続出現が0回のデータなんて出てこないですよね。あと、1回と2回の場合は別にこの方法をやっても小さくならないし。とかいうことで、もうちょっと工夫もできそうですね。

とりあえずなんも工夫せずに、

回数(1byte) データ(1byte)

の連続形式にエンコードするプログラムを書いた。
enc.c。標準入力から得たデータをRLEにかけて標準出力にあうとぷっと。

#include <stdio.h>

int main(){
  unsigned char buf[2], count;
  count = 1;
  fread(&buf[0], 1, 1, stdin);
  while(fread(&buf[1], 1, 1, stdin) != 0){
    if(buf[0] != buf[1] || count == 255){
      fwrite(&count, 1, 1, stdout);
      fwrite(&buf[0], 1, 1, stdout);
      count = 1;
    } else {
      ++count;
    }
    buf[0] = buf[1];
  }
  return 0;
}

dec.c。標準入力から得たRLEなデータを復号して標準出力に。

#include <stdio.h>

int main(){
  unsigned char buf, count;
  while(fread(&count, 1, 1, stdin) != 0){
    fread(&buf, 1, 1, stdin);
    for(;count>0;--count)
      fwrite(&buf, 1, 1, stdout);
  }
  return 0;
}

こんなんを

% gcc enc.c -o enc
% gcc dec.c -o dec

コンパイルして、

% cat hoge
aaaaaaabc            aaaabbbbbbbbccccc
ccccccccccccaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbeeeeee
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
% cat hoge |./enc >hoge.rle
% ll hoge*
-rw-r--r--    1 sun31048 J03A          135 Nov 19 20:16 hoge
-rw-r--r--    1 sun31048 J03A           30 Nov 19 20:17 hoge.rle
% rm -f hoge
% ll hoge*
-rw-r--r--    1 sun31048 J03A           30 Nov 19 20:17 hoge.rle
% cat hoge.rle |./dec >hoge
% ll hoge*
-rw-r--r--    1 sun31048 J03A          135 Nov 19 20:17 hoge
-rw-r--r--    1 sun31048 J03A           30 Nov 19 20:17 hoge.rle
% cat hoge
aaaaaaabc            aaaabbbbbbbbccccc
ccccccccccccaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbeeeeee
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

できたー。

% cat jpn.txt |./enc >jpn.txt.rle
% ll jpn.txt*
-rw-r--r--    1 sun31048 J03A       231295 Nov 19 19:16 jpn.txt
-rw-r--r--    1 sun31048 J03A       443822 Nov 19 20:19 jpn.txt.rle

うはー、これはひどい

test