ページ 1 / 1
txtファイルの圧縮
Posted: 2012年6月02日(土) 23:29
by ares
コード:
#include <stdio.h>
#include <stdlib.h>
void func(FILE *fp1, FILE *fp2)
{
int c1, c2, l = 0;
for(c1 = c2 = fgetc(fp2); c1 != EOF; c2 = fgetc(fp2)){
if(c1 != c2){
fprintf(fp1, "%c%d", c1, l);
l = 1;
c1 = c2;
}
else l++;
}
}
int main(void)
{
FILE *fp1 = fopen("before.txt", "w"), *fp2 = fopen("after.txt", "r");
if(!fp1 || !fp2) exit(EXIT_FAILURE);
func(fp1, fp2);
fclose(fp1);
fclose(fp2);
return 0;
}
もともと存在するtxtファイルのbefore.txtをランレングス圧縮するプログラムを作りたいのですが
ただ、before.txtには数字も含まれています
Re: txtファイルの圧縮
Posted: 2012年6月02日(土) 23:40
by へにっくす
ares さんが書きました:コード:
#include <stdio.h>
#include <stdlib.h>
void func(FILE *fp1, FILE *fp2)
{
int c1, c2, l = 0;
for(c1 = c2 = fgetc(fp2); c1 != EOF; c2 = fgetc(fp2)){
if(c1 != c2){
fprintf(fp1, "%c%d", c1, l);
l = 1;
c1 = c2;
}
else l++;
}
}
int main(void)
{
FILE *fp1 = fopen("before.txt", "w"), *fp2 = fopen("after.txt", "r");
if(!fp1 || !fp2) exit(EXIT_FAILURE);
func(fp1, fp2);
fclose(fp1);
fclose(fp2);
return 0;
}
もともと存在するtxtファイルのbefore.txtをランレングス圧縮するプログラムを作りたいのですが
ただ、before.txtには数字も含まれています
何がしたいのでしょう?
掲示しているソースをみる限り、
after.txtを読み込んでbefore.txtに書き込む処理のように見えますが。
before.txtは結果なので、数字も含まれるのは当然な気がしますが、、
Re: txtファイルの圧縮
Posted: 2012年6月02日(土) 23:59
by softya(ソフト屋)
仕様レベルの質問でしょうか?
長さを表すのに数値文字を使っているので続けて数字の文字があると切れ目がわからない問題があると思います。
そこを如何に解決するかお考えでしょうか?
Re: txtファイルの圧縮
Posted: 2012年6月06日(水) 15:56
by ares
返信をいただいた方の意見を参考に作りなおしてみたのですが
http://gihyo.jp/book/2010/978-4-7741-4307-1/support
でダウンロードできるtxtファイルを圧縮してみたところファイルが大きくなってしまいました。
問題点などがあればっぜひお願いします。
コード:
#include <stdio.h>
#define ABCD 0x1b
void encode(FILE *fp1, FILE *fp2)
{
int ch, tmp, count = ' ';
tmp = EOF;
while ( EOF != (ch = fgetc(fp1)) ) {
if ('~' == count)
tmp = EOF;
if (tmp == ch)
count++;
else if (' ' == count)
fputc(ch, fp2);
else {
fputc(ABCD, fp2);
fputc(count, fp2);
fputc(ch, fp2);
count = ' ';
}
tmp = ch;
}
if (' ' != count) {
fputc(ABCD, fp2);
fputc(count, fp2);
}
}
int main(void)
{
FILE *fp1, *fp2;
fp1 = fopen("before.txt", "r");
fp2 = fopen("after.txt", "w");
if (NULL == fp1 || NULL == fp2) {
puts("error");
return 0;
}
encode(fp1, fp2);
fclose(fp1);
fclose(fp2);
return 0;
}
Re: txtファイルの圧縮
Posted: 2012年6月06日(水) 16:10
by softya(ソフト屋)
テキストモードでのランレングス圧縮ですから元より大きくなる可能性が高いと思います。
例えバイナリでも工夫しないと元より大きくなる可能性が高いのがランレングスですので。
以前の質問にお応えいただいていませんが、今の仕様を説明していただいても良いですか?
その方が早いと思います。
Re: txtファイルの圧縮
Posted: 2012年6月06日(水) 16:42
by ares
>>softya(ソフト屋)さん
こういうことでよろしいですか?今回は前の投稿であげたURLからダウンロードできるデータを半分以下のサイズに圧縮するプログラムをつくりなさいという課題で自分は圧縮に関して無知に等しかったので基本的なランレングス圧縮を採用したのですがバイナリにしなければ難しいですかね?
コード:
void encode(FILE *fp1, FILE *fp2)
{
int ch, tmp, count = ' ';
tmp = EOF;
while ( EOF != (ch = fgetc(fp1)) ) {
if ('~' == count) /* 繰り返し数が限界の場合の処理 */
tmp = EOF;
if (tmp == ch) /* 直前の文字と同じなら繰り返しとする */
count++;
else if (' ' == count)/* 1文字だけの出力 */
fputc(ch, fp2);
else {
fputc(ABCD, fp2);
fputc(count, fp2);
fputc(ch, fp2);/* 繰り返しの処理はABCDを出力し、繰り返し数を出力する。新しく読んだ文字を出力 */
count = ' ';
}
tmp = ch;
}
if (' ' != count) {
fputc(ABCD, fp2);
fputc(count, fp2);/* 繰り返しの処理が残っているとき */
}
}
Re: txtファイルの圧縮
Posted: 2012年6月06日(水) 17:11
by softya(ソフト屋)
while抜けで残っていた時の処理で文字が出力されていません。
[ABCD][count][ch]でセットですよね。
あと、これだと2文字以上連続した時に3文字分を消費しますので元より確実に大きくなるでしょう。
4文字以上連続しない限り圧縮コードを出さないように工夫すべきです。
※ 元よりは大きくなりませんが小さくなる可能性も低いと多いと思います。
このアルゴリズムのままバイナリにしても3バイトが2バイトになるぐらいで大きな効果は期待できません。
半分のサイズまで圧縮するならランレングスよりも辞書法やあるいはデータの特性に注目した圧縮方法を採用すべきでしょう。
それと、URLからダウンロードできるデータの文字コードはshift-jisでは無いみたいですが処理はshift-jis前提なのも問題でしょう。バイナリとして処理したほうが良いのでは?