皆様、はじめまして。
この度、急ぎでプログラムをC言語で作成するように命じられました。
C言語は経験が無いと断ったのですが、要員確保が出来ない為、何とかしてくれとのこと。
本来なら自分で学習しながら、作成すべきなのですが、超短納期の為、その時間が取れません。
今回は誠に申し訳ないのですが、皆様のお力をお借り出来ないでしょうか。
宜しくお願いいたします。
仕様概要
・CSVファイルを読み込み、2カラム目の項目(文字型)で昇順ソート(qsort)を行う。
・ソートされた2カラム目の同一値毎に1カラム目(数値型)が最大値となるレコードを抽出する。
・抽出されたレコードを新規CSVファイルに出力する。
入力CSV概要
・レコード件数は日によって変わる
・カラム数は8つ
・各カラムの項目長は可変長
・上記に伴いレコード長も可変長
入力ファイル例
39,"AAA3","B1","C1","D1","E1","F1","G1"
100,"AAA1","B2","C2","D2","E2","F2","G2"
101,"AAA2","B3","C3","D3","E3","F3","G3"
105,"AAA1","B4","C4","D4","E4","F4","G4"
102,"AA1","B5","C5","D5","E5","F5","G5"
99,"AAA2","B6","C6","D6","E6","F6","G6"
1019,"AAA3","B7","C7","D7","E7","F7","G7"
処理後に出力されるファイル
102,"AA1","B5","C5","D5","E5","F5","G5"
105,"AAA1","B4","C4","D4","E4","F4","G4"
101,"AAA2","B3","C3","D3","E3","F3","G3"
1019,"AAA3","B7","C7","D7","E7","F7","G7"
A 回答 (6件)
- 最新から表示
- 回答順に表示
No.6
- 回答日時:
もう、結構時間がたったから良いかな。
いかにソースを示します。
とりあえず30分くらいで書いてみました。
例のCSVデータは問題なく動作します。
しかし、意図的にバグを埋めています。
解析して勉強してください。
#include <stdio.h>
#include <string.h>
typedef struct {
int c1;
char c2[7][2048];
} CSVTBL;
CSVTBL *csvtbl;
static int cmpstring(const void *p1, const void *p2)
{
CSVTBL *lp1, *lp2;
lp1 = (CSVTBL *)p1;
lp2 = (CSVTBL *)p2;
int ret = strcmp(lp1->c2[0], lp2->c2[0]);
if (ret == 0 ) {
if (lp1->c1 == lp2->c1) {
ret = 0;
}
else {
ret = lp1->c1>lp2->c1?-1:1;
}
}
return ret;
}
main (int argc, char *argv[])
{
char buf[2049];
char *b;
int i;
int num=0;
if(argc != 3) {
fprintf(stderr, "input error !\n");
fprintf(stderr, "usage:%s INFILENAME OUTFILENAME\n", argv[0]);
return -1;
}
csvtbl = (CSVTBL *)malloc(sizeof(CSVTBL));
FILE *fpr = fopen(argv[1], "r");
FILE *fpw = fopen(srgv[2], "w");
if(fpr && fpw) {
while(fgets(buf, 2049, fpr)) {
if (strlen(buf) <2048) {
csvtbl = (CSVTBL *)realloc(csvtbl, sizeof(CSVTBL)*(num+1));
b = strtok(buf, ",");
if (b) {
csvtbl[num].c1 = atoi(b);
for(i=0; i<7; i++) {
b = strtok(NULL, ",");
if(b) {
strcpy(csvtbl[num]c2[i], b);
}
else {
fprintf(stderr, "record error! : [%s]\n", buf);
break;
}
}
}
num ++;
}
else {
fprintf(stderr, "record error! : [%s]\n", buf);
while(fgets(buf, 2049, fpr)) {
if (strlen(buf) < 2048) break;
}
}
}
qsort(csvtbl, num, sizeof(CSVZTBL),cmpstring);
fprintf(fpw, "%d,%s,%s,%s,%s,%s,%s,%s", csvtbl[0].c1,csvtbl[0].c2,csvtbl[0].c3,csvtbl[0].c4,csvtbl[0].c5,csvtbl[0].c6,csvtbl[0].c7);
for (i=1; i<num; i++) {
if (0!=strcmp(csvtbl[i-1].c2[0], csvtbl[i].c2[0])) {
fprintf(fpw, "%d,%s,%s,%s,%s,%s,%s,%s", csvtbl[i].c1,csvtbl[i].c2,csvtbl[i].c3,csvtbl[i].c4,csvtbl[i].c5,csvtbl[i].c6,csvtbl[i].c7);
}
}
fclose(fpw);
fclose(fpr);
}
free(csvtbl);
return 0;
}
No.5
- 回答日時:
こんにちは。
処理の概略手順だけ考えてみました。
※下記は一例です。
1)入力元CSVファイルをオープンする。
2)入力元のCSVファイルを行単位に読み込み、その行数のみ取得する。
・fgets関数で、最大バッファ長を (2048+4)ぐらいとして、行単位に[EOF]
になるまで読み込んで(※ここでは文字列バッファに読み込むのみ)、
行数(レコード数)をカウントする。
・読み込んだ1行分の文字列の末尾の改行文字('\n')を除いた文字数が
2048文字を超えた行は無視する。(※カウントしない)
<行数(レコード数)を格納する変数の例>
long nRecCnt; ← 取得した行数(レコード数)を格納する。
3)取得した行数分の、データ構造体(1レコード相当)の配列を確保する。
<1レコード分のデータ構造体の例>
typedef struct TT_DATA {
long nNum; /* 1カラム目の数値データ用 */
char szItem[256]; /* 2カラム目の文字列データ用 */
char szOther[2048]; /* 3カラム目以降のデータ用 */
int nOutFlag; /* CSV出力の識別フラグ */
} T_DATA;
※上記の文字列データのサイズは適当に割り振ってあります。
実際は、仕様に合わせて調整する必要があります。
※3カラム目以降のデータは、プログラム上で編集する必要がないので、
1つの文字列として取り込むように、1つのバッファにしてあります。
※CSV出力の識別フラグ(nOutFlag)は、出力CSVファイルに書き込む
レコードを識別するためのフラグに使用します。
上記の構造体の場合で、行数分(レコード数分)の配列を確保する場合、
T_DATA *t_data;
t_data = (T_DATA *)malloc( sizeof(T_DATA) * nRecCnt );
※nRecCnt は取得した行数(レコード数)
のような感じになります。
4)入力元のCSVファイルのファイルポインタを先頭に戻して(先頭へシークする)
再び、1行毎に読み込みながら、3)で確保した構造体配列に、全行数分の
データを格納する。
・読み込んだ1行分の文字列の末尾の改行文字('\n')を除いた文字数が、
2048文字を超えた行は無視する。(※データは取り込まない)
・1カラム目のデータは、「数字文字列→数値」変換を行い、.nNum に格納する。
・2カラム目のデータは、.szItem[] に格納する。
・3カラム目以降のデータは、1つの文字列として、.szOther[] に格納する。
・データ構造体の「CSV出力の識別フラグ」(.nOutFlag)は、0 でクリアしておく。
5)入力CSVファイルをクローズする。
6)データを取り込んだ、構造体配列に対して、2カラム目のデータ(文字列)をキー
にしてソート処理を行い、並び替える。
・文字列の大小判定は、strcmp関数で判定可能かと思います。
7)ソート後の構造体配列の先頭からデータを参照し、2カラム目の文字列が
同じものについて、1カラム目の数値が最大のものを抽出し、
「CSV出力の識別フラグ」(.nOutFlag)に 1 を立てる
処理を行う。
8)出力CSVファイルをオープンする。
9)データ構造体配列を先頭から参照し、「CSV出力の識別フラグ」が 1 のもの
について、出力CSVファイルに書き込む処理を行う。
10)出力CSVファイルをクローズする。
11)確保したメモリを解放して、プログラムを終了する。
以上のような処理が考えられると思います。
的外れだった場合はすみません。
参考になれば幸いです。
おはようございます。
ご回答有難う御座います。
どのような手順で作成したらいいのかさっぱりでしたので
大変参考になりました。
この週末になんとかご提示頂いた手順でC言語の参考書を読みながら
コーディング出来るように努力してみます。
本当に有難う御座いました。
No.4
- 回答日時:
> 皆様のお力をお借り出来ないでしょうか。
で、なにが問題なんですか?
おはようございます。
言葉足らずで申し訳ありませんでした。
どのような手順でどのようなコードを書けばいいのか
さっぱり分からなかった為、その辺りについて
お教え頂きたかったのです。
これからは万人に分かるような書き方をするように心がけます。
No.3
- 回答日時:
> ・各カラムの項目長は可変長
この「可変長」の部分がひっかかります。
可変長でもかまいませんが、長さの上限はあるのでしょうか?
上限が設定されていないのであれば、reallocでバッファを拡張しながら読み込まないといけませんので、未経験者がいますぐ取り組むのは絶望的です。
こんばんは。
仕様を再確認しました。
各カラムの項目長は決まってないらしいのですが、
レコード長の上限は2048らしいです。
つまりカラムの項目長上限も決まってるようなものですね!
レコード的に2048を超えるレコードが存在した場合、
そのレコードは処理対象外とするそうです。
おいおい、最初と話が違うだろ・・・と言いたかったです。
No.2
- 回答日時:
とりあえず、昇順に並び替える所まで挑戦してみた。
--------
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define STRING_MAX 2048
#define FIELD_MAX 256
#define RECORD_MAX 16384
#define STRING_BUF 16384
typedef struct scsvrec{
char chr[FIELD_MAX][STRING_MAX];
}SCSVREC;
typedef struct scsvdat{
long record_cnt;
SCSVREC *dat[RECORD_MAX];
}SCSVDAT;
bool csvFileRead(char *filename ,SCSVDAT *csvDat);
SCSVREC* csvResolution(char *buf);
int main(int argc,char *argv[])
{
bool bRet = false;
SCSVDAT *cdat;
SCSVREC *swpwk;
long ilp1,ilp2;
FILE *fout;
cdat = (SCSVDAT*)malloc(sizeof(SCSVDAT));
memset(cdat ,0 ,sizeof(SCSVDAT));
if (argc > 1) {
bRet = csvFileRead(argv[1], cdat);
}
if (bRet == false) return 0;
if (cdat->record_cnt >= 2) {
swpwk = (SCSVREC*)malloc(sizeof(SCSVREC));
for (ilp1 = cdat->record_cnt - 2 ; ilp1 > 0 ; ilp1--) {
for(ilp2 = 0 ; ilp2 < ilp1 ; ilp2 ++) {
if (strcmp(cdat->dat[ilp2]->chr[1] ,cdat->dat[ilp2+1]->chr[1]) > 0) {
memcpy(swpwk ,cdat->dat[ilp2] ,sizeof(SCSVREC));
memcpy(cdat->dat[ilp2] ,cdat->dat[ilp2+1] ,sizeof(SCSVREC));
memcpy(cdat->dat[ilp2+1] ,swpwk ,sizeof(SCSVREC));
}
}
}
}
if (argc > 2) {
fout = fopen(argv[2] ,"w");
if(fout == NULL){
printf("出力ファイルが開けませんでした。\n");
return 0;
}
for (ilp1 = 0 ; ilp1 < cdat->record_cnt ; ilp1++) {
fprintf(fout,"%s,%s,%s\n",cdat->dat[ilp1]->chr[0],cdat->dat[ilp1]->chr[1],cdat->dat[ilp1]->chr[2]);
}
fclose(fout);
}
return(0);
}
bool csvFileRead(char *filename ,SCSVDAT *csvDat)
{
FILE *fp;
SCSVREC *onerec;
bool ret = false;
char buf[STRING_BUF];
memset(csvDat ,0 ,sizeof(SCSVDAT));
fp = fopen(filename ,"r");
if(fp == NULL){
printf("入力ファイルが開けませんでした。\n");
return(false);
}
while(fgets(buf,sizeof(buf),fp) != NULL){
if (buf[strlen(buf)-1] == '\n'){
buf[strlen(buf)-1] = '\0';
}
if (strlen(buf) >0) {
onerec = csvResolution(buf);
csvDat->dat[csvDat->record_cnt] = onerec;
(csvDat->record_cnt)++;
}
}
fclose(fp);
return (true);
}
SCSVREC* csvResolution(char *buf)
{
int bcnt, rcnt, mcnt;
bool dblfld;
SCSVREC *onedat;
onedat = (SCSVREC*)malloc(sizeof(SCSVREC));
memset(onedat ,0 ,sizeof(SCSVREC));
bcnt = rcnt = mcnt= 0;
dblfld = false;
for(;;bcnt++) {
if (buf[bcnt] == '\0') break;
if (mcnt == 0 && buf[bcnt] == '\"') {
dblfld = true;
continue;
}
if (dblfld == false && buf[bcnt] == ',') {
rcnt++;
mcnt = 0;
continue;
}
if (dblfld == true && buf[bcnt] == ',') {
onedat->chr[rcnt][mcnt] = buf[bcnt];
mcnt++;
continue;
}
if (dblfld == true && buf[bcnt] == '\"' && buf[bcnt+1] == '\"') {
onedat->chr[rcnt][mcnt] = '\"';
mcnt++;
bcnt++;
continue;
}
if (dblfld == true && buf[bcnt] == '\"' && (buf[bcnt+1] == ',' || buf[bcnt+1] == '\0')) {
rcnt++;
mcnt = 0;
bcnt++;
dblfld = false;
continue;
}
onedat->chr[rcnt][mcnt] = buf[bcnt];
mcnt++;
}
return onedat;
}
こんばんは。回答有難うございます。
今、出先の為、帰社してから試してみようと思うのですが、かなりやっかいそうですね。取り敢えず少しでも進むように頑張ってみます。
No.1
- 回答日時:
「超短納期」で「C言語は経験が無い」人にやらせるって, この時点ですでに無理筋だよなぁ....
さておき, どうしても C じゃないとダメなの? ほかのスクリプト系言語ならもっと簡単にできるはずなのに. 各カラムのデータにカンマ (,) がないなら Perl では
%records;
while (<>) {
$data = [split /,/];
next if exist $records{$data->[1]} && $records{$data->[1]}->[0] > $data->[0];
$records{$data->[1]} = $data;
}
for (sort { $a <=> $b; } keys %records) {
print join(',', @{$records{$_}});
}
くらいで終わりなのに.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Visual Basic(VBA) 顧客ごとに違う点検案内を作成するマクロ 4 2022/09/16 05:34
- Visual Basic(VBA) マクロを教えてください。 7 2023/06/01 19:47
- 実用・教育 その著者まで亡くなられたのですか? 2 2022/07/30 17:55
- その他(家族・家庭) 幼い2人の子は、孤児になるのでしょうか?? 1 2022/07/31 15:01
- Excel(エクセル) Formulaプロパティーを使ってセルに数式を組んだのですが簡潔にしたい。 3 2022/08/21 20:51
- その他(パソコン・スマホ・電化製品) (追加質問)(モバイル)ミニブックPCのオーディオ出力をパワーアップする(電池駆動)アンプ機材 3 2023/02/27 17:35
- 政治 自民・萩生田光一政調会長「防衛増税前に解散、国民に信を問う」……国民をナメきってませんか? 4 2022/12/25 19:19
- 人類学・考古学 ドローンを飛ばして間近で古墳調査をするのって、宮内庁の許可は必要なのかな? 5 2023/03/04 09:07
- 政治 佐渡金山の推薦書不備に怒りの声……こういうのに、統一教会の意向を受けた売国議員が暗躍してませんか? 2 2022/07/31 19:18
- Excel(エクセル) EXCEL 行内のデータを2行に分けて、表を作り直したいのです。教えてください。 5 2023/06/25 14:00
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
構造体のメンバにファイルポイ...
-
【C言語】ファイルを読み込んで...
-
c言語でのfscanfについて
-
fgets( ) の返り値は何?
-
Winsockの通信処理にてファイル...
-
ADボードでリアルタイムサンプ...
-
fopenでファイル名に、変数を使...
-
C言語でファイル読み書きを早く...
-
漢字を配列に入れたいのですが
-
c言語 ファイルから数字を読み...
-
ファイル出力で改行を入れたい!
-
InternetReadFileを使ったファ...
-
ファイルへの書込み処理が異常...
-
C言語 連番データの読み込み
-
バイナリファイルの読み込み(C...
-
ガンマ変換 C言語でプログラ...
-
プログラムの内で、何か画面表...
-
辞書順にソートしたいのですが...
-
a*(1-exp(-bx))+cの近似の方法
-
同時にファイル読み込み 書き込み
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
c言語でのfscanfについて
-
fopenでファイル名に、変数を使...
-
複数ファイルの同時読み込みの...
-
C言語でセグメンテーションエ...
-
C言語でファイル読み書きを早く...
-
ファイル出力で改行を入れたい!
-
エラーがわかりません、、
-
テキストファイル内に対して, ...
-
構造体のメンバにファイルポイ...
-
C言語にてXMLファイルから任意...
-
ガンマ変換 C言語でプログラ...
-
【C言語】ファイルを読み込んで...
-
日本語ファイル名のFTPについて
-
fscanfでループしてしまう。
-
CRC32の計算方法
-
fgets( ) の返り値は何?
-
VisualStudioでのファイルの入...
-
ファイルに行番号を追加
-
ファイルへの書込み処理が異常...
-
ファイルが読み込めない・・・
おすすめ情報