掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.28029

指定した桁での折り返し
投稿者---ナトー(2006/09/03 20:40:39)


連続して質問してすみません。
vis関数(入力ファイル中の表示可能文字列のみを出力ファイルにコピーする関数)で、出力ファイルにコピーする際に指定した桁数で行を折り返して表示するオプションを付けたいのですがどうもうまくいきません。
以下のように変数jとWIDTHを追加してみたのですが指定したWIDTHの長さで折り返しされません。
表示する際にjがWIDTH以上になると改行を入力するようにしてみましたがこのやり方はよくないのでしょうか?

void vis(char *name,FILE *fin)
{
FILE *fout;
int c, i ,j;
char buf[BUFSIZ], outfile[SIZE]="out_";

strcat(outfile,name);

if((fout=fopen(outfile,"w"))==NULL){
printf("cannot open file!\n");
}

do{
for(i=0,j=0;(c=getc(fin)) != EOF ;){
if(!isprint(c)){
break;
}
buf[i++]=c;
if(i >= BUFSIZ)
break;
}
if(j >= WIDTH){ //ここからが変更した点です
fprintf(fout,"\n"); //j >= WIDTHなら改行
j=0;         //j=0に初期化
}
else{
fprintf(fout,"%.*s\n",i, buf); //j < WIDTHなら表示
j++;             //jをインクリメント
}
}while (c != EOF);

fclose(fout);
}


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:指定した桁での折り返し 28030 nano 2006/09/03 20:50:48
<子記事> Re:指定した桁での折り返し 28031 nano 2006/09/03 22:31:20
<子記事> Re:指定した桁での折り返し 28034 shu 2006/09/03 23:51:07


No.28030

Re:指定した桁での折り返し
投稿者---nano(2006/09/03 20:50:48)


>表示する際にjがWIDTH以上になると改行を入力するようにしてみましたがこのやり方はよくないのでしょうか?

do文によるループの先頭にあるfor文の中で、
毎回jをゼロに初期化するのは正しいでしょうか?


この投稿にコメントする

削除パスワード

No.28031

Re:指定した桁での折り返し
投稿者---nano(2006/09/03 22:31:20)


>表示する際にjがWIDTH以上になると改行を入力するようにしてみましたがこのやり方はよくないのでしょうか?

ファイル名の設定やオープン/クローズを除いた
主要な処理の流れは、おおよそ以下のような感じでできると思います。
あくまでも一つの例ですが…。

1.出力文字数をゼロに初期化する。
2.入力ファイルが読み取れる間、以下を繰り返す。
2-1.読み取った1文字が表示可能であれば、
2-1-1.出力する。
2-1-2.出力文字数をインクリメントする。
2-1-3.出力文字数が行の幅以上ならば、
2-1-3-1.改行する。
2-1-3-2.出力文字数をゼロに初期化する。

というわけで、この例に沿うと、もともと提示されていたvis関数で、
・変数i, bufは不要
・do文によるループは不要
となります。


この投稿にコメントする

削除パスワード

No.28034

Re:指定した桁での折り返し
投稿者---shu(2006/09/03 23:51:07)


//	step1
{
    while ((c = getchar()) != EOF) {
        putchar(c);
    }
}

//	step2
{
    while ((c = getc(fin)) != EOF) {
        putc(c, fout);
    }
}

//	step3
{
    while ((c = getc(fin)) != EOF) {
        if (isprint(c)) {
            putc(c, fout);
        }
        else {
            fprintf(fout, "\\X%X", c);
        }
    }
}

//	step4
{
    while ((c = getc(fin)) != EOF) {
        if (isprint(c)) {
            putc(c, fout);
        }
        /* else {
            fprintf(fout, "\\X%X", c);
        } */
        
        //
        if (???) {
            putchar('\n');
        }
    }
}

//	step5
{
    for (i = 0; (c = getc(fin)) != EOF; i++) {
        if (isprint(c)) {
            putc(c, fout);
        }
        /* else {
            fprintf(fout, "\\X%X", c);
        } */
        
        //
        if (???) {
            putchar('\n');
        }
    }
}



この投稿にコメントする

削除パスワード

No.28039

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/04 17:35:05)


shuさん、nanoさんありがとうございます。
以下のように作り直してみたのですが、やっぱりめちゃくちゃな表示になってしまいます。どこがおかしいのでしょうか?

void vis(char *name,FILE *fin)
{
FILE *fout;
int c, i;
char buf[BUFSIZ], outfile[SIZE]="out_";

strcat(outfile,name);

if((fout=fopen(outfile,"w"))==NULL){
printf("cannot open file!\n");
}

do{
for(i=0;(c=getc(fin)) != EOF;i++){
if(isprint(c)){
putc(c,fout);
}
else{
//fprintf(fout,"\\X%X",c);
break;
}

if(i >= WIDTH){
putc('\n',fout);
i=0;
}
}
}while(c != EOF);

fclose(fout);
}


この投稿にコメントする

削除パスワード

No.28040

Re:指定した桁での折り返し
投稿者---nano(2006/09/04 18:02:32)


とりあえず、do〜とfor〜の二重のループはいらないのと、
変数 i の値を適宜出力するための printf関数を挿入してみてください。


この投稿にコメントする

削除パスワード

No.28042

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/04 18:37:33)


do-whileループをなくして、printf("%d\n",i)を挿入してみたところ、i=0しか出力されず(止まってる?)出力ファイルが空になってしまいました。


if((fout=fopen(outfile,"w"))==NULL){
printf("cannot open file!\n");
}

for(i=0;(c=getc(fin)) != EOF;i++){
printf("%d\n",i);
if(isprint(c)){
fprintf(fout,"%c",c);
}
else{
//fprintf(fout,"\\X%X",c);
break;
}

if(i >= WIDTH){
fprintf(fout,"\n");
i=0;
}
}

fclose(fout);


この投稿にコメントする

削除パスワード

No.28043

Re:指定した桁での折り返し
投稿者---iijima(2006/09/04 18:45:31)


> do-whileループをなくして、printf("%d\n",i)を挿入してみたところ、
> i=0しか出力されず(止まってる?)出力ファイルが空になってしまいました。

最初の文字でisprintが偽を返し、break文でforループを抜けたからだと思われます。



この投稿にコメントする

削除パスワード

No.28041

Re:指定した桁での折り返し
投稿者---iijima(2006/09/04 18:33:55)


すでに指摘があったようにdo〜whileは不要と思われます。

現在は、forループ内のbreak文によってisprint関数が偽を返すたびにforループが始まり、
そのときにiが0に初期化されます。
その結果、意図通りの出力にならないのだと思います。

do〜whileを使っている意図は分かりませんが、もしそれを生かすならばiはその前で
初期化すべきです。

また、桁数をWIDHに揃えるのは、isprintが真を返したときに出力する文字に対して
だけだと推測しますが、違いますか?
もしそういうことであれば、iをインクリメントするのは文字を出力したときだけで
良いと思います。

# ソースは「HTML変換ツール」で字下げしてください。


この投稿にコメントする

削除パスワード

No.28045

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/04 18:55:52)


iijimaさんアドバイスありがとうございます。
ご指摘どおりbreak文の部分を省いたら一応WIDTHどおりに折り返してくれるようになったのですが、出力を確認すると全ての桁数がWIDTHになってしまっていました。これでは逆に見にくくなってしまうので、文字列ごとに改行を入れたいのですが、このやり方ではそれはできないでしょうか?

 for(i=0;(c=getc(fin)) != EOF;){
    //printf("%d\n",i);
    if(isprint(c)){
      fprintf(fout,"%c",c);
      i++;
    }

    if(i >= WIDTH){
      fprintf(fout,"\n");
      i=0;
    }
  }





この投稿にコメントする

削除パスワード

No.28046

Re:指定した桁での折り返し
投稿者---nano(2006/09/04 18:59:13)


>これでは逆に見にくくなってしまうので、

えっ、そういう仕様じゃなかったんですか…。これは驚きです。

>文字列ごとに改行を入れたいのですが、

文字列と他の文字列を区別するには、
何を頼りにすればいいのでしょうか?


この投稿にコメントする

削除パスワード

No.28047

Re:指定した桁での折り返し
投稿者---nano(2006/09/04 19:01:44)


ちょっと訳がわからなくなってきました。
そこで、入力ファイル中のすべての文字が表示可能であると仮定して、
「こんな入力を与えたとき、こんな出力がほしい」という
例を挙げていただけませんか?


この投稿にコメントする

削除パスワード

No.28049

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/04 19:24:32)


すみません。説明が下手だったみたいです。
先ほどのプログラムを

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbb
ccccccccccccccccccccccccccccccccccccccccc
ddddd
eeeeeeeee


というファイルで実行すると

aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaabbbb
bbbbcccccccccccccccc
cccccccccccccccccccc
cccccdddddeeeeeeeee

こういう出力になってしまうのです。
でもそうではなくて

aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaa
bbbbbbbb
cccccccccccccccccccc
cccccccccccccccccccc
c
ddddd
eeeeeeeee



とこんな感じの出力にしたい、という意味でした。


この投稿にコメントする

削除パスワード

No.28050

Re:指定した桁での折り返し
投稿者---nano(2006/09/04 20:27:34)


改行するタイミングが増えました。
1)指定文字数を出力するたびに改行
2)前の出力文字と違っていたら改行

2)を実現するにはどんな情報を管理すればよいか、
考えてみてください。


この投稿にコメントする

削除パスワード

No.28053

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/04 23:35:34)


nanoさんありがとうございます。

>2)前の出力文字と違っていたら改行

これはどういう意味なのでしょうか?


この投稿にコメントする

削除パスワード

No.28055

Re:指定した桁での折り返し
投稿者---nano(2006/09/05 08:10:01)


まさに、今行なおうとしていることです。
a を何文字か出力していて b に変わったとき、
その b が前に出力した文字(a)と異なるため、
改行した後で b を出力する、という意味です。


この投稿にコメントする

削除パスワード

No.28051

Re:指定した桁での折り返し
投稿者---iijima(2006/09/04 20:33:38)


出力文字数が指定した桁数(WIDTH)に達したとき、または直前に出力した文字と異なる
ときに改行を出力する、ということですね。

# または〜の説明が欠落していたので仕様が正しく伝わりませんでした。


方法はいくつか考えられますが、例えば次のようなのはどうでしょうか。


    「直前に出力した文字コードを表す変数(例えばprev)を宣言する」

    prev = 「初期値」; // 「初期値」は文字コードとしてあり得ない値
    for( i = 0; ( c = getc( fin ) ) != EOF; ){
        if( isprint( c ) ){
            if( WIDTH <= i || 「prevが初期値でなく、かつ、cがprevと異なる」 ){
                putc( '\n', fout );
                i = 0;
            }
            putc( c, fout );
            i++;
            「prevの値をcに更新する」
        }
    }


「」内の具体的なコードを考えてみてください。
最初の文字の出力のときに改行させないために、prevの初期値に文字コードとして
あり得ない値を与えるのがミソです。

forループの前に最初の1文字の出力まで行い、prevを最初の1文字のコードで初期化
するという方法もありますね。



この投稿にコメントする

削除パスワード

No.28052

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/04 23:31:13)


iijimaさん、ありがとうございます。
以下のようにしてみたのですが、今度は一文字ずつの改行になってしまいました。どこか悪いのでしょうか?

prev=128;
  for(i=0;(c=getc(fin)) != EOF;){
    if(isprint(c)){
      if(i >= WIDTH || (prev != 128 && c != prev)){
    fprintf(fout,"\n");
    i=0;
      }
      fprintf(fout,"%c",c);
      i++;
      prev=c;
    }
  }




この投稿にコメントする

削除パスワード

No.28057

Re:指定した桁での折り返し
投稿者---nano(2006/09/05 09:41:41)


WIDTHの値が1以下になっている、ということはないですよね?


この投稿にコメントする

削除パスワード

No.28058

Re:指定した桁での折り返し
投稿者---nano(2006/09/05 11:26:07)


あるいは、入力ファイル中に連続した文字の並びがないときも
そうなりますね。
例えば、
ababcabcd
を読み込ませると、同じ文字が登場はしますが連続はしていないため、出力は
a
b
a
b
c
a
b
c
d
となります。


この投稿にコメントする

削除パスワード

No.28059

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/05 20:08:22)


すみません・・・また説明が悪かったみたいです。
例えばWIDTH=10として

abcdefghijklmnopqrstuvwxyz
aiueo
koizumijunichiro
okayama

これを入力ファイルとして処理すると

abcdefghij
klmnopqrst
uvwxyz
aiueo
koizumijun
ichiro
okayama

というふうにしたかったんです。
それで以下のようなコードを作ってみました。

do{
    for(i=0;(c=getc(fin)) != EOF ;){
      if(!isprint(c)){
    break;
      }
      buf[i++]=c;
      if(i >= BUFSIZ)
    break;
    }
    buf[i++]='\0';
    printf("%s\n",buf);
    for(j=0;buf[j]!='\0';j++){
      if(j >= WIDTH){
    fprintf(fout,"\n");
    j=WIDTH;
    WIDTH+=WIDTH;
      }
      else{
    fprintf(fout,"%c",buf[j]);
    j++;
      }
    }
    fprintf(fout,"\n");
  }while (c != EOF);




bufには文字列が一つ格納されているので、bufに対して折り返しの処理をするのが一番簡単かなと思い上のようにしてみたのですが、どうもちゃんと折り返しできてないみたいです。


この投稿にコメントする

削除パスワード

No.28060

Re:指定した桁での折り返し
投稿者---nano(2006/09/05 20:48:36)


こんなのでいかがでしょう。

    while (fgets(buf, sizeof(buf), fin) != NULL) {
        buf[strlen(buf)-1] = '\0';
        for (i = j = 0; buf[i];) {
            if (isprint(buf[i])) {
                if (j >= WIDTH) {
                    putc('\n', fout);
                    j = 0;
                }
                putc(buf[i], fout);
                i++, j++;
            }
        }
        putc('\n', fout);
    }




この投稿にコメントする

削除パスワード

No.28061

Re:指定した桁での折り返し
投稿者---nano(2006/09/05 21:11:08)


間違えました。
    while (fgets(buf, sizeof(buf), fin) != NULL) {
        buf[strlen(buf)-1] = '\0';
        for (i = j = 0; buf[i]; i++) {
            if (isprint(buf[i])) {
                if (j >= WIDTH) {
                    putc('\n', fout);
                    j = 0;
                }
                putc(buf[i], fout);
                j++;
            }
        }
        putc('\n', fout);
    }




この投稿にコメントする

削除パスワード

No.28062

Re:指定した桁での折り返し
投稿者---かずま(2006/09/05 22:15:52)


    int c, i = 0;

    while ((c = getc(fin)) != EOF)
        if (c == '\n' || isprint(c) && putc(c, fout) && ++i >= WIDTH)
            putc('\n', fout), i = 0;



この投稿にコメントする

削除パスワード

No.28064

Re:指定した桁での折り返し
投稿者---iijima(2006/09/06 08:56:02)


> すみません・・・また説明が悪かったみたいです。

# 仕様を正確に説明、理解する訓練もしましょうね。


No.28045で投稿されたコードを再利用して最小限の修正をした例。

    for( i = 0; ( c = getc( fin ) ) != EOF; ){
        if( isprint( c ) ){
            fprintf( fout, "%c", c );
            i++;
        }
        if( i >= WIDTH || c == '\n' ){ // ★
            fprintf( fout, "\n" );
            i = 0;
        }
    }

★印の行で「cの値が'\n'に等しい場合」という条件を加えただけです。



この投稿にコメントする

削除パスワード

No.28083

Re:指定した桁での折り返し
投稿者---ナトー(2006/09/08 09:53:05)


みなさんのおかげでなんとか出来ました。
ありがとうございました。


この投稿にコメントする

削除パスワード

No.28048

Re:指定した桁での折り返し
投稿者---iijima(2006/09/04 19:12:02)


> 出力を確認すると全ての桁数がWIDTHになってしまっていました。

スレッドの題名、最初のご説明、提示されたソースから、私もそれが仕様だと思いました。
仕様を明確にしていただかないと、これ以上の検討はできません。



この投稿にコメントする

削除パスワード

No.28044

Re:指定した桁での折り返し
投稿者---shu(2006/09/04 18:52:38)


>shuさん、nanoさんありがとうございます。
>以下のように作り直してみたのですが、やっぱりめちゃくちゃな表示になってしまいます。どこがおかしいのでしょうか?

前のスレッドのもともとのナトーさんのコードでのforループと、
shuの書いたサンプルプログラム中のforループとでは、意図が違います。

ナトーさんのforループが主にbufに代入するためのループだったのに対し、
shuのサンプルプログラムでのforループでは、単に改行のタイミングの為に用意したものでした。

その違いを踏まえた上で、プログラムを読みなおしてみてください。



この投稿にコメントする

削除パスワード

No.28056

Re:指定した桁での折り返し
投稿者---shu(2006/09/05 09:07:06)


//	step6
{
    for (i = 0; isprint(c = getc(fin)); i++) {
        putc(c, fout);
        
        if (???) {
            putc('\n', fout);
        }
    }
}

//	step7
{
    for (i = 0; isprint(c = getc(fin)); i++) {
        putc(c, fout);
        
        if (???1) {
            putc('\n', fout);
        }
    }
    
    if (???2) {
        putc('\n', fout);
    }
}

//	step8
{
    do {
        for (i = 0; isprint(c = getc(fin)); i++) {
            putc(c, fout);
            
            if (???1) {
                putc('\n', fout);
            }
        }
        
        if (???2) {
            putc('\n', fout);
        }
    } while (c != EOF);
}

//	step9
{
    while (fgets(buf, sizeof(buf), fin)) {
        for (i = 0; isprint(buf[i]); i++) {
            putc(buf[i], fout);
            
            if (???1) {
                putc('\n', fout);
            }
        }
        
        if (???2) {
            putc('\n', fout);
        }
    }
}

//	step10
{
    while (fgets(buf, sizeof(buf), stdin)) {
        for (i = 0; isprint(buf[i]); i++) {
            putchar(buf[i]);
            
            if (???1) {
                putchar('\n');
            }
        }
        
        if (???2) {
            putchar('\n');
        }
    }
}

//	step11
{
    do {
        for (i = 0; isprinf(c = getchar()); i++) {
            putchar(c);
            
            if (???1) {
                putchar('\n');
            }
        }
        
        if (???2) {
            putchar('\n');
        }
    } (c != EOF);
}

//	step12
{
    do {
        for (i = 0; isprinf(c = getchar()); i++) {
            putchar(c);
            
            if (???1 || ???2') {
                putchar('\n');
            }
        }
    } (c != EOF);
}



この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧