性格いい人が優勝

fscanfでCSVファイルから文字列を取り込み、カンマ区切りで4つの変数に文字列を代入しようと考えているのですが、出力されたcsvファイルが変わった区切りかたをしているのでうまく変数に代入できずに困っております。

例えば、出力されたcsvファイルは以下のようになっております

"ABC CO.,I","4540",""STAR"","2010/03/31"

希望としては
aにABC CO.,I
bに4540
cにSTAR
dに2010/03/31
をそれぞれ代入したいのですが
aに入る文字列にはCO.,Iというようにカンマが既にありますので
カンマ区切りで読み込むとめちゃくちゃになってしまいます

ですので基準をダブルクオーテーションに置き、"と"の間の文字列を代入というような形が取れれば良いのですが、このような方法での文字列取得は可能でしょうか?

c言語の勉強を始めて間もない為、低レベルな質問、表現であることをお許し下さい。
よろしくお願いします。

A 回答 (2件)

"の回数を判定する変数を用意すれば、ご要望を満たせると思います。


//"を数える変数
int count=0;
//csvの内容が入った文字列とする
char str[];
//strのインデックス数(≒csvファイルの文字数)
int length;

char a[256],b[256],c[256],d[256];
//jはabcd配列のインデックスに使う
int i,j;
for(i=0; i<length; i++){
//"をカウント
if(str[i] == '"'){
count++;
continue;
}

//"が偶数の時
if(!(count % 2))
j=0;
//"が1~2の間はaに代入
else if(count == 1){
a[j] = str[i];
j++;
}
//"が3~4の間はbに代入
else if(count == 3){
b[j] = str[i];
j++;
}
//以下略...
}


ただ、この方法だと「文字列内に"がある場合」には上手くいきません。
csvには規定があるので、下記リンク20行ほどを読まれると良いです。
http://dobon.net/vb/dotnet/file/readcsvfile.html
C#であれば、これをコピペするだけで解決なんですけどね。
せめてC++であれば、上記相当のプログラムは書けると思いますが……。
    • good
    • 0
この回答へのお礼

素晴らしいです!
よくそんなアイディアが浮かびますね!!
sankaku197様は幅広い経験をお持ちなのですね

初心者の私は雷に打たれたような感じです(笑)
本当にありがとうございました。

お礼日時:2010/02/27 21:41

このカテゴリでCSVについて何度も出ているため、一応汎用化を目指して組んでみたプログラムを晒します。



昔の事なので、どこまでデバッグ出来ていたのか覚えていません。

---------------------------------
#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);
bool isKanji(unsigned char c);

int main()
{
 bool bRet;
 SCSVDAT *cdat;
 char filename[1024] = "sample.csv";

 cdat = (SCSVDAT*)malloc(sizeof(SCSVDAT));
 bRet = csvFileRead(filename, cdat);

 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';
  }
  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 (isKanji((unsigned char)buf[bcnt])) {
   onedat->chr[rcnt][mcnt] = buf[bcnt];
   mcnt++;
   bcnt++;
   onedat->chr[rcnt][mcnt] = buf[bcnt];
   mcnt++;
   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;
}

bool isKanji(unsigned char c)
{
 bool ret = false;
 if ((0x81 <= c && c <= 0x9f) || (0xE0 <= c && c <= 0xEF)) {
  ret = true;
 }
 return (ret);
}
    • good
    • 0
この回答へのお礼

私への質問の回答の為にここまで参考になる情報を提供してくださいまして
心から感謝しております。

是非活用させていただきます
本当にありがとうございます。

お礼日時:2010/02/27 21:43

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!