ファイルの中身のソート

[戻る]
エハラ [E-Mail] 2003/02/05(水) 17:42:12
はじめまして、エハラと申します。
Cでファイルを読込み、ファイルの中身をソートしなおして新しいファイルを作成したいのですがどうす
ればよいのでしょうか?教えてください。
よろしくお願いします。

下記みたいな感じで今頑張ってますが、どうやってソートすればよいか分かりません。ただのバ
ブルソートなら分かるんですが、レコードの97〜100まででソートして新しいファイルを作成って言
うのが???

97〜100には必ず値が入っています。0001〜9999までで、0000も入っています。
1レコード256+CRLFです。

元ファイル名 AA.dat
1レコード目.〜0003
2レコード目.〜0000
3レコード目.〜0002
4レコード目.〜0001
5レコード目.〜0000
こんな感じです。0000以外は複数入っていません。
これを
ソート後ファイル名 BB.dat
1レコード目.〜0001
2レコード目.〜0002
3レコード目.〜0003
4レコード目.〜0000
5レコード目.〜0000
の順番にしたいのです。

int main(int argc, char *argv[])
{
  FILE    *fin,*fout;        // ファイルポインタ
  char    s[258];
  char    dum[30960];
  char    f[256];
  int    iRtn = 0;
  int    b,e,d,i;
  int    iLoop = 0;
  char    a;
  char    c;

    printf("argc= %d \n",argc);

    memset(&s[0], 0x00, 258);
    memset(&dum[0], 0x00, sizeof(dum));

    if (argc == 3){
        //File open
        i = 0;
        if( (fin=fopen( argv[1], "r" ))==NULL) {        
    /* 入力ファイルオープン */
        printf("ファイルの中身を確認して下さい。\n");
        exit(1);
        }
        if( (fout=fopen( argv[2], "w" ))==NULL) {        
    /* 出力ファイルオープン */
        printf("出力ファイルがオープンできません\n");
        exit(1);
        }
        while(fgets(s,256,fin)!=NULL) {// 入力ファイルから読み込んだデ
ータを    //
            printf("out b = %d\n",b);    //100byte目をチェック
            fputs(s,fout);        //出力ファイルに書き込み
        }

        printf("0 :%s \n",argv[0]);
        b = 0;
        while(fgets(s,258,fin)!=NULL) {
           printf("inner = %x b = %d\n",s[99],b);    //100byte目をチ
ェック
            iRtn = (strncmp(&s[96], "0000", 4));
            strncpy((char *)&dum ,&s[96],4);
            if (iRtn != 0){//97〜100までが0000以外の時
              printf("inner = %d b = %d% d\n",dum,b,iRtn);
            }        
            b = b+1;
        }
        while(fgets(s,256,fin)!=NULL) {
            printf("out b = %d\n",b);
            fputs(s,fout);
          }
    }
    else{    // 引数が3以外のとき
        exit(1);
    }
        fclose(fin);                    
    /* 入力ファイルクローズ */
        fclose(fout);                    
    /* 出力ファイルクローズ */

    return(0);
}

tib 2003/02/05(水) 18:21:12
このソースでは、ソートを試みているようには見えないのですが。

・2つの文字列を比較してどちらが大きいかをチェックする関数を別に作る
・入力ファイルの内容を1行ずつ、全て読み込んで1つの配列に格納する
・qsort()を使ってソートする
・ソート済みの配列を出力ファイルに書き出す

という手順になると思います。

エハラミホ [E-Mail] 2003/02/05(水) 22:30:53
tibさんのおっしゃる通りでソートは試みてないです。T_T
ファイル開いてからどのようにソートして新しいファイルを作成すればよいかが分からないので
す。どうか教えてください。
よろしくお願いします。

YuO [E-Mail] 2003/02/05(水) 22:36:08
一旦メモリに蓄えてqsort呼び出すのが簡単だと思いますよ。

暇人貴子 2003/02/05(水) 22:40:49
qsort()の仕様については調べられましたか?
>・2つの文字列を比較してどちらが大きいかをチェックする関数を別に作る
この関数をqsortの引数に渡してやることで、コールバックされます。
ですので、strncmp等を使ってキーとなるオフセットの位置の文字列の大小を
比較してあげればよいのでは?
もちろん、strncmpで比較する前にキーが"0000"だったときの処理が必要ですが・・・

wood 2003/02/05(水) 23:06:31
最初のハンドル名と違うけど エハラミホ さんは質問者と同一人物なんですよね

1.ファイルオープンする
2.読み込み(格納はしない) レコード件数のカウントするだけ
3.ファイル クローズ
4.件数分格納できるだけの領域を用意する
5.ファイルオープンする
6.読み込み(4で用意した領域へ格納する)
7.ファイルクローズ
8.あなたが知っているバブルソートで4で用意した領域内のデータをソートする
  qsortでもいいですけどご自分の理解可能なほうでどうぞ

9.出力ファイル オープン
10.ソート結果の4で用意した領域から1レコード分づつ出力ファイルへ書き込む
11.出力ファイルクローズする
12.終了

エハラミホ [E-Mail] 2003/02/06(木) 23:32:32
はい、同一人物ですよ。江原美帆です。
こんなんで良いのですかね?頭がぐるぐるですT_T

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

#define BUFLEN 300

int cmp(const void *c1, const void *c2);

int main(int argc, char *argv[])
{
  FILE *fin, *fout;
  int i, size;
  char buf[BUFLEN], *line;
  
  if (argc != 3) exit(1);
  if ((fin = fopen(argv[1], "r")) == NULL) {        /* 入力ファイルオープン */
    printf("入力ファイルがオープンできません\n");
    exit(1);
  }

  fseek(fin,0,SEEK_END); /* ファイルの末尾にシーク */
  size=ftell(fin)+1;     /* 現在の位置を取得 */
  rewind(fin);           /* ファイル先頭にまき戻す */

  
  if ((line = (char **)malloc(sizeof(char *) * size)) == NULL) exit(1);
  for (i = 0; i < size; i++)
    
  //sort

  if ((fout = fopen(argv[2], "w")) == NULL) {       /* 出力ファイルオープン */
    printf("出力ファイルがオープンできません\n");
    exit(1);
  }

  fclose(fout);
  
  free(line);
  
  return 0;
}

エハラミホ [E-Mail] 2003/02/06(木) 23:47:06
qsortはこんな感じでよいのでしょうか。
って、helpに載っていたまんまなんです.........

〜
qsort(line, lc, sizeof(char *), cmp);
〜

int cmp(const void *c1, const void *c2)
{
  return strncmp((const char *)c1 , (const char *)c2 , 4);
}
(

επιστημη 2003/02/07(金) 00:31:14
> qsortはこんな感じでよいのでしょうか。

やってみてはいかがです?

RAPT 2003/02/07(金) 02:37:20
http://www.bohyoh.com/CandCPP/FAQ/FAQ00047.html

wood 2003/02/07(金) 08:13:43
多分だめだね
>ソート後ファイル名 BB.dat
>1レコード目.〜0001
>2レコード目.〜0002
>3レコード目.〜0003    ←ここと@
>4レコード目.〜0000    ←ここ A
>5レコード目.〜0000
>の順番にしたいのです。
出力したい大小関係が @とAで逆転しているでしょ

>RAPT 2003/02/07(金) 02:37:20
http://www.bohyoh.com/CandCPP/FAQ/FAQ00047.html
参考に、多少のアルゴリズム付け加えないとだめですよ

だから私は皆さんが「qsort」と書いているのを
あえて「バブルソート」と書いたつもりだったんですけどね
実は「バブルソート」のアルゴリズムもわからないのでは?

>8.あなたが知っているバブルソートで4で用意した領域内のデータをソートする

>1レコード256+CRLFです。
この条件はどこへ行っちゃったの「size」がギガ単位だったらどうなるの?

>if ((line = (char **)malloc(sizeof(char *) * size)) == NULL) exit(1);

実際にやってみてエラーが出たり、コンパイルエラー解決できなかったら
また相談に乗りますよ

επιστημη 2003/02/10(月) 10:14:03
ご参考: C++版サンプル

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <functional>
 
int main() {
  std::vector<int> v;
  for ( int i = 0; i <9; ++i ) {
    v.push_back(9-i);
    v.push_back(0);
  }
  std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout," "));
  std::cout << std::endl;

  std::vector<int>::iterator position =
    std::partition(v.begin(), v.end(), 
                   std::bind1st(std::not_equal_to<int>(),0));
  std::sort(v.begin(), position);
  
  std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout," "));
  std::cout << std::endl;

  return 0;
}

--- 結果 ---
9 0 8 0 7 0 6 0 5 0 4 0 3 0 2 0 1 0 
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 0 0 0 

...できた^^;

wood 2003/02/10(月) 12:11:05
この人
>Cでファイルを読込み
って きちんとC言語でって断ってますけど
エハラ さんの提示しているソースにもC++でのコーディング入っていない
とおもいますが

επιστημη さんのは 参考になるんでしょうか
答え方勘違いしてませんか?

επιστημη 2003/02/10(月) 12:16:20
あ....ごめんなさい。

では上記C++コードでやっていること:

[1] ソート対象外である要素を配列の端に追い詰める
[2] と同時に、ソート対象である要素は配列のどこまでかを調べる。
[3] 配列の先頭から[2]までをソートする。

これなら Cで実装する参考になるかしら。

エハラミホ 2003/02/10(月) 18:22:41
[[解決]]
いろいろありがとうございます。
いろんな方に教えていただき解決することができました。
また何かあった時はよろしくお願いします。

2003/02/10(月) 18:34:09
解決なさったのは喜ばしい事ですが、できればどのように解決なさったのか示して戴ければ
後々(のちのち)別の方々への参考になると思います

エハラミホ 2003/02/15(土) 11:37:07
遅くなってすみません。いろいろ忙しくて......
教えてくださった皆さんありがとうございました。
下記の方法で解決!!しました。


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

#define BUFLEN 300

int cmp(const void *c1, const void *c2);

void main(int argc, char *argv[])
{
  FILE *fin, *fout;                //ファイルポインタ
  int i, lc;                    //ループカウンタ、ファイル数
  char buf[BUFLEN], **line;
  
  if (argc != 3) exit(1);
  if ((fin = fopen(argv[1], "r")) == NULL) {            // 入力ファイルオープン 
    printf("入力ファイルがオープンできません\n");
    exit(1);
  }
    
  for (lc = 0; fgets(buf, BUFLEN, fin); lc++);
  // printf("lc = %d",lc);
  rewind(fin);
  
  
 if ((line = (char **)malloc(sizeof(char *) * lc)) == NULL) exit(1);

  for (i = 0; i < lc; i++)
     
    if ((line[i] = (char *)malloc(BUFLEN)) == NULL) exit(1);
  
  for (i = 0; i < lc && fgets(line[i], BUFLEN, fin); i++);

  fclose(fin);

  qsort(line, lc, sizeof(char *), cmp);

  if ((fout = fopen(argv[2], "w")) == NULL) {           // 出力ファイルオープン 
    printf("出力ファイルがオープンできません\n");
    exit(1);
  }

  for (i = 0; i < lc; i++) fputs(line[i], fout);
 

  fclose(fout);
  for (i = 0; i < lc; i++) free(line[i]);
  free(line);
  return;
}

int cmp(void const *c1, void const *c2){
 
  if (!strncmp(*(const char **)c1 + 96, "0000", 4)) return 1;
  if (!strncmp(*(const char **)c2 + 96, "0000", 4)) return -1;
  if (!strncmp(*(const char **)c1 + 96, "    ", 4)) return 1;
  if (!strncmp(*(const char **)c2 + 96, "    ", 4)) return -1;

  return strncmp(*(const char **)c1 + 96, *(const char **)c2 + 96, 4);
}

古いスレッドには追加発言できません。