C言語関係掲示板

過去ログ

No.1050 文字列のソート

[戻る] [ホームページ]
No.13682

文字列のソート
投稿者---セバスチャン(2004/04/21 21:13:04)


初めて投稿します。
今C言語を勉強中の新米セバスチャンです。

早速ですが今悩んでる問題があります。
それは、下記の配列をfgetcで読み込み、それを並び替えするというものです。
<配列>
ファイル名:TEST

都府 頭文字 市外局番
-----------------------
Tokyo  T     03
Osaka  O    06
-----------------------
上記配列をfgetcで読み込み、
-----------------------
03   T    Tokyo
06   O    Osaka
-----------------------
というように順番を入れ替える場合、

if((fp=fopen("TEST","r"))==NULL){
fprintf("can't open file"\n);
}
while((c=fgetc(fp))!=EOF){
    処理
}
-----------------------------------
とここから文字cをどのように都県、頭文字、市外局番に結び付けて
並び替えをしていけばいいのでしょうか。
fgetsとかfscanfは使用してはいけないという問題です。

皆様の良きアドバイスをお願いします。


No.13683

Re:文字列のソート
投稿者---nop(2004/04/21 23:28:00)


>それは、下記の配列をfgetcで読み込み、それを並び替えするというものです。
><配列>
>ファイル名:TEST

ファイルと配列は別物だぞ。
あと、その手の処理はfgets()など、行単位で処理するものだぞ。

悪いことは言わない、もっと言語仕様やアルゴリズム、データ構造などを学んでから作れ。

No.13684

Re:文字列のソート
投稿者---ぽこ(2004/04/21 23:43:14)


>if((fp=fopen("TEST","r"))==NULL){
>fprintf("can't open file"\n);
>}
>while((c=fgetc(fp))!=EOF){
>    処理
>}
>-----------------------------------
>とここから文字cをどのように都県、頭文字、市外局番に結び付けて
>並び替えをしていけばいいのでしょうか。

文字cが都県、頭文字、市外局番を区切る文字(スペース?タブ?)であったとき、
それまで読み込んだ文字をひとつの要素(都県または頭文字または市外局番)と
見なせば良いのではないでしょうか?

No.13698

Re:文字列のソート
投稿者---セバスチャン(2004/04/22 22:30:52)


>>if((fp=fopen("TEST","r"))==NULL){
>>fprintf("can't open file"\n);
>>}
>>while((c=fgetc(fp))!=EOF){
>>    処理
>>}
>>-----------------------------------
>>とここから文字cをどのように都県、頭文字、市外局番に結び付けて
>>並び替えをしていけばいいのでしょうか。
>
>文字cが都県、頭文字、市外局番を区切る文字(スペース?タブ?)であったとき、
>それまで読み込んだ文字をひとつの要素(都県または頭文字または市外局番)と
>見なせば良いのではないでしょうか?
-------------------------------------------------------------------
ご回答ありがとうございます。

頭の中ではわかっていても実際にソースコードをかくとなると何をどのように使用していけばいいのでしょうか。
ヒントなんてあったら教えてください。
fgetcは1文字づつ読んでいくから・・・スペース或いは改行コードがあればストップして、そこまでの文字を文字列として格納して・・・云々・・・。
実際にはどうやってやれば・・・。
すみませんがやり方を教えてください。
よろしくおねがいします。

No.13700

Re:文字列のソート
投稿者---RAPT(2004/04/23 01:50:26)


isalpha()とかisspace()とか
このis〜()系の関数について調べてみてください。

No.13722

Re:文字列のソート
投稿者---セバスチャン(2004/04/24 14:20:52)


>isalpha()とかisspace()とか
>このis〜()系の関数について調べてみてください。
------------------------------------------------------------------
ご回答ありがとうございます。
isalphaやisspaceをしらべてみました。
------------------------------------------------------------------
#include <stdio.h>

int main(void)
{
FILE *fpin;
int c;
char s[256];
char *ken,*inl,*tel;
int i,m=0;
int tel_no;

if((fpin=fopen("TEST","r"))==NULL)
printf("can't open\n");
else{
while((c=fgetc(fpin))!=EOF){
if(isalpha(c))
s[m]=c; /*s[m]に格納?*/
m++;

      /*この間の処理方法がまわりません*/

}
printf("%s %s %d\n",tel_no,ini,ken);
fclose(fpin);
}
return 0;
}
--------------------------------------------------------------
すみません、ここまでは考えたのですが間の処理が分かりませんでした。
イメージとしては、スペースがくるまでfgetcで読み込んでそこまでを
”都府”とし、次のスペースがくるまで再度読み込み、”頭文字”とする。最後は改行がくるまでを読み込み”市外局番”とする。というイメージはしてます。しかしながらその処理の中身をソースコードで表すには、
どのような処理を考えたらよいのでしょうか。
以上ヒントをお願いします。


No.13725

Re:文字列のソート
投稿者---RAPT(2004/04/24 17:10:30)


fgetc()は面倒なので、ご自分でどうぞ。
fgets()+sscanf()での実現例。

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  FILE *fpin = NULL;
  char s[BUFSIZ], ken[BUFSIZ], ini[BUFSIZ], tel[BUFSIZ];

  fpin = fopen("TEST.txt", "r");
  if(fpin == NULL){
    printf("can't open\n");
    exit(1);
  }

  while(fgets(s, BUFSIZ, fpin) != NULL){
    if(3 != sscanf(s, " %s %s %s", ken, ini, tel)){
      fprintf(stderr, "データ不正:%.50s\n", s);
      exit(1);
    }
    printf("%s\t%s\t%s\n", tel, ini, ken);
  }
  fclose(fpin);

  return 0;
}


No.13728

Re:文字列のソート
投稿者---セバスチャン(2004/04/24 17:33:27)


><pre>fgetc()は面倒なので、ご自分でどうぞ。

fgetsでの実行例ありがとうございます。
fgetcでの実行はやってみますが、
------------------------------------------
if(isalpha(c))
s[m]=c; /*s[m]に格納?*/
m++;
------------------------------------------
このかき方は間違ってませんでしょうか。
int型のcをchar型のsにというのはどうも抵抗があるのですが。
宜しくアドバイスお願いします。

No.13730

Re:文字列のソート
投稿者---RAPT(2004/04/24 18:01:05)


fgetc()で書いてみた。
ただし、マルチバイト文字を含むデータを想定していない。

int型のcをchar型のsにというのはどうも抵抗があるのですが。
今回のケースでは問題ありません。
極々簡単に言うと、エラー判定にchar型では表現できないからです。

(char)-1 == 0xff で、(unsigned char)0xff == 255 となるが、
バイナリデータの場合など、0xffは有効なデータとなりうるので、
そのままでは使えない。そこで、拡張し、int型にした。

そういった訳なので、今回の場合はキャストしてしまって問題ありません。


#include <stdio.h>    // FILE, BUFSIZ, EOF, fgetc, feof, printf, fprintf
#include <stdlib.h>   // exit
#include <string.h>   // memset
#include <ctype.h>    // isspace, isalpha, isdigit

// 任意の文字タイプのデータをバッファにコピーし、コピーしたバイト数を返す
int getValue(char *pBuff, int bufsiz, FILE *fp, int (*pfn)(int))
{
  int c, i;

  // バッファをゼロクリア
  memset(pBuff, 0, bufsiz);

  // 空白文字類をスキップ
  for(c = fgetc(fp); c != EOF && isspace(c); c = fgetc(fp));

  // 該当文字をコピー
  for(i = 0; i < bufsiz && c != EOF; i++){
    if(!pfn(c)){
      break;
    }
    *pBuff = (char)c;
    pBuff++;
    c = fgetc(fp);
  }
  return i;
}

int main(void)
{
  FILE *fpin = NULL;
  char ken[BUFSIZ], ini[BUFSIZ], tel[BUFSIZ];

  fpin = fopen("TEST.txt", "r");
  if(fpin == NULL){
    printf("can't open\n");
    exit(1);
  }

  for(;;){
    if( 0 == getValue(ken, BUFSIZ, fpin, isalpha) || 
        0 == getValue(ini, BUFSIZ, fpin, isalpha) ||
        0 == getValue(tel, BUFSIZ, fpin, isdigit) )
    {
      if(!feof(fpin)){
        // ファイルの終端以外でデータの解析に失敗
        fprintf(stderr, "データが不正です。\n");
      }
      break;
    }
    printf("%s\t%s\t%s\n", tel, ini, ken);
  }
  fclose(fpin);

  return 0;
}


No.13731

Re:文字列のソート
投稿者---セバスチャン(2004/04/24 18:51:38)


>>RAPTさん
ありがとうございます。参考にさせていただきます。
自分でも再度がんばってみますのでわからないところがあったら
またお願いします。

No.13741

Re:文字列のソート
投稿者---セバスチャン(2004/04/25 13:06:31)


早速ですみません。
教えてください。
ここの部分がいまいち理解できませんでした。

// 該当文字をコピー</font>
for(i = 0; i < bufsiz && c != EOF; i++){
-------------------------------------------------
ここのbufsizというのは何をさいているのでしょうか。
-------------------------------------------------
<pre>if(!pfn(c)){
break;
}

</pre>

上記はpfn(c)が偽(0)であればbreakとする、ということと思いますが、

<pre>*pBuff = (char)c;
pBuff++;
c = fgetc(fp);

</pre>
上記のpBuffはcの値をコピーしpBuff++するとありますが、
このpBuff++がいまいち理解できません。
お手数ですがもう少し説明頂きたく思います。

return i;

あとこのreturn iの'i’に戻すというところも理解ができませんでした。

なにぶん初心者ですので宜しくお願いします。

No.13742

Re:文字列のソート
投稿者---RAPT(2004/04/25 13:29:51)


コメント・ソースを読んで下さい。コメント周辺に色々と書いてあります。

>  // 該当文字をコピー</font>
>  for(i = 0; i < bufsiz && c != EOF; i++){
>-------------------------------------------------
>ここのbufsizというのは何をさいているのでしょうか。
>-------------------------------------------------
関数の第2引数です。第1引数で指定したバッファの有効サイズを意味します。
>> int getValue(char *pBuff, int bufsiz, FILE *fp, int (*pfn)(int))
これは、関数の呼び出し
>> getValue(ken, BUFSIZ, fpin, isalpha)
を見れば分かるかと。BUFSIZ はstdio.hで定義。σ(^^)の環境では512

> if(!pfn(c)){
>   break;
> }
>上記はpfn(c)が偽(0)であればbreakとする、ということと思いますが、
そうです。

> *pBuff = (char)c;
> pBuff++;
> c = fgetc(fp);
>
>上記のpBuffはcの値をコピーしpBuff++するとありますが、
>このpBuff++がいまいち理解できません。
「いまいち」? はっきり「何が」わからないのか、明記してください。

>お手数ですがもう少し説明頂きたく思います。
嫌です。σ(^^)はあなたに説明する義務はありません。
文字列・ポインタについての勉強をご自分でなさってください。

> return i;
>あとこのreturn iの'i’に戻すというところも理解ができませんでした。
だーかーらー、コメント読めってば。
>> // 任意の文字タイプのデータをバッファにコピーし、コピーしたバイト数を返す

コピーしたバイト数==0ってことは、正常にコピーしたデータはない、
すなわち、データの不整合を意味する、とみなしています。
※なお、各データは任意のF該当しない文字集合1バイト以上で
 区切られているという前提のコードです。すなわち、"abc def012" だと、
 3つ目の読み出し結果は"012"ではなく、"12"となる、ってこと。

>なにぶん初心者ですので宜しくお願いします。
「初心者」というキーワードを免罪符にしようとする人は嫌いです。
自助努力する意識を身に付けてください。


No.13733

Re:文字列のソート
投稿者---かずま(2004/04/24 19:29:57)


> while((c=fgetc(fpin))!=EOF){
> if(isalpha(c))
> s[m]=c; /*s[m]に格納?*/
> m++;
>
>       /*この間の処理方法がまわりません*/
>
> }
> printf("%s %s %d\n",tel_no,ini,ken);

【掲示板ご利用上の注意】にしたがってソースを添付してください。
    int c, i, m, t = 0;  char s[256];

    while ((c = fgetc(fp)) != EOF)
        switch (t) {
        case 0: if (!isspace(c)) s[0] = c,    m = t = 1; break;
        case 1: if ( isalpha(c)) s[m++] = c; else t = 2; break;
        case 2: if (!isspace(c)) i = c,           t = 3; break;
        case 3: if (!isspace(c)) putchar(c),      t = 4; break;
        case 4: if ( isdigit(c)) putchar(c);
                else  printf("\t%c\t%.*s\n", i, m, s),  t = 0;
        }    


No.13736

Re:文字列のソート
投稿者---セバスチャン(2004/04/25 01:05:27)


>【掲示板ご利用上の注意】にしたがってソースを添付してください。

ご回答ありがとうございます。
また掲示板での注意点について、分からなかった為、字下げをわすれてました。すみません。
かずまさんのコードも参考にさせて頂きます。
またよろしくお願いします。