- ベストアンサー
CでCSVファイルを扱う
いつもお世話になっております。 今回はCSVファイルの扱いについてお聞きしたいです。 現在、 "hoge","hogehoge","…","…" というようなCSVファイルを扱いたいと思い、いろいろ試しているのですがなかなかうまくいきません。 CSVの各行をgetlineで取得して、カンマで分けるだけならできたのですが、","のまとまりで分けたいのです。現在は文字で分割はできるのですが文字列で分割する方法がわかりません。 ","で分けたい理由はたとえば"hoge,hoge"という文字列をカンマで分けてしまうと二つに分かれてしまいそれを避けたいです。 分割点の前後の文字から判断しようともしてみましたがうまくいきませんでした。 アドバイスなどありましたらご教授願います。 現在は以下のようになっております。 ifstream ifs; string temp; LPCTSTR str; ifs.open("test.csv", ios::in); while(getline(ifs, temp)) { str = strtok(const_cast<char*>(temp.c_str()), _T(",")); printf("%s\n", str); while(str != NULL) { str = strtok(NULL, ","); if (str != NULL) { printf("%s\n", str); } } } 以上のもので CSVの"1","2","3","4" が"1"と"2"と"3"と"4"になります。 これを1と2と3と4にしたいです。 よろしくお願いします。 環境はWindowsXP VisualStudio6.0 MFC未使用 です。お願いします。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
C だけど、参考になれば、 #include <stdio.h> #include <string.h> int main(void) { char str[] = "\"1\",\"2,2\",\"33,3\",\"444,4\",\"5555,5\"", *p = str + 1, *q; char buf[10][32]; int i, j; for(i = 0; q = strstr(p, "\",\""); i ++){ *q = '\0'; strcpy(buf[i], p); p = q + 3; } *strchr(p, '\"') = '\0'; strcpy(buf[i], p); for(j = 0; j <= i; j ++) puts(buf[j]); return 0; }
その他の回答 (6)
- yama5140
- ベストアンサー率54% (136/250)
>ダブルクォーテーションに囲まれているカンマを無視するために三文字が連続(◆)しているときに分割したいということです。 No.6 さんのデータ例(*)をつかわせていただき、「ポインタ」を使わずに作ってみました。 ◆3文字目はチェックしていません・・、あしからず。 (BorlandC++5.6.4) *:「ファイル」を想定し、\n を付加 #include <stdio.h> void main() { char cBuf[256] = "\"1\",\"2,2\",\"33,3\",\"444,4\",\"5555,5\"\n"; int i, iTop; // CSVファイル オープン // while( NULL != fgets( cBuf, 256, fp ) ){ printf( "%s\n", cBuf ); for( iTop = i = 1; i < 256; i++ ){ if( '"' != cBuf[ i ] ) continue; i++; // 連続して if( '\n' == cBuf[ i ] ){ // 行末 cBuf[ i - 1 ] = 0; printf( "%s\n", &cBuf[ iTop ] ); break; // 1レコード処理終了 } if( ',' == cBuf[ i ] ){ // 「◆仕様」区切り cBuf[ i - 1 ] = 0; printf( "%s\n", &cBuf[ iTop ] ); i += 2; // 次のブロック iTop = i; } } // } // CSVファイル クローズ } 注:インデントに全角空白を用いています。タブに一括変換して下さい。
お礼
ご回答ありがとうございます。 こちらも試したところ、思ったことができるようです。 3文字目のチェックをしていないとのことですが、よく考えて、必要ない時はそうしたいと思います。
- JaritenCat
- ベストアンサー率37% (122/322)
1文字ずつ調べるしかないと思います。 昔作ったプログラム例がありますので、よかったら参考にどうぞ。 http://jariten.dip.jp:8000/up/src/up0022.zip ダブルクォーテーションがない場合も、複数改行も対応しているつもりです。(Excelが吐くcsvにあわせました)
お礼
ご回答ありがとうございました。 動作確認しました。思ったように動いてました。
- jacta
- ベストアンサー率26% (845/3158)
strtokでは役不足です。 二重引用符の中には改行文字が含まれることもあるでしょうから、std::getlineでも不十分です。 結論としては、状態遷移を管理しながら一文字ずつ処理するか、yaccのようなパーサジェネレータを使うかです。 せめて、Visual C++ 6.0ではなく、Visual C++.NET 2003ぐらいであれば、Boost.Spiritを使えば簡単にできるのですが...
補足
ご回答ありがとうございます。 ダブルクォーテーション内に改行が入る可能性は今回は無いです。 ですのでgetlineを使っています。 strtokで難しいとなると、地道に一文字ずつ見ていくしかないのでしょうか? 出来ればスマートにやりたかったのですが、一度地道にやってみます。
- asuncion
- ベストアンサー率33% (2127/6289)
> CSVの"1","2","3","4" が"1"と"2"と"3"と"4"になります。 > これを1と2と3と4にしたいです。 "1"という文字列ではなく、整数の1を得たいのですか? "hoge"という文字列からは何を得たいですか?
補足
ご回答ありがとうございます。 説明不足であったため補足させていただきます。 例が悪かったです。たとえば "12,34","56,78","1111","2222" という文字列があったらカンマで分けると "12と34"と"56と78"と"1111"と"2222"の六つに分かれてしまいます。 今実現したいのはカンマで分けるのではなく <",">の三文字が連続しているときに分けたいということで上記例だと 12,34と56,78と1111と2222の四つに分割したいです。 ダブルクォーテーションに囲まれているカンマを無視するために三文字が連続しているときに分割したいということです。 わかりにくい説明かもしれませんがアドバイスお願いします。
- redfox63
- ベストアンサー率71% (1325/1856)
strtokの引数string2に渡すものを工夫してやればいいのでは? "自体は \でエスケープしてやれば文字リテラルに含められます "\"" で "1つの文字列を定義できます "\",\""で "," を渡せますよ
補足
ご回答ありがとうございます。 アドバイスの点はすでに試してみましたが、出力を見ると <",">の三文字連続出現という意味ではなく "と,と"の各文字で分割するという意味でカンマだけの時より 細かく分かれてしまいました。
- annyG
- ベストアンサー率25% (10/39)
「"1"」を渡すと「1」が返ってくる関数を一つ作れば解決ではないでしょうか?
補足
ご回答ありがとうございます。 No3の方の捕捉に書かせていただきましたが、例の書き方が悪く、混乱させてしまっているようですいません。 今困っているのは、ダブルクォーテーションの間にカンマが入ってしまうときの対処として<",">の三文字が連続しているとき分割したいというものでした。 わかりにくい説明ですがアドバイスがありましたらよろしくお願いします。
お礼
ご回答ありがとうございました。 まさにこのようなことがやりたかったです。 これを少しカスタムして完全に理想のものができました。 ありがとうございました。