csvファイルをfscanfで読み込もうとしているのですが
どうしてもおかしな文字が混じってしまいます
例えばcsvファイルのデータが
abc,efg
となっているとします
これを読み込みprintfで表示すると
abc"" efg""
というように表示されてしまいます
csvファイルを普通に開いてもこのような文字はありません
一体どこから沸いて出てくるのでしょうか?
%[^]を使って不要な文字を読み込まないように
%[^"]と記述しましたが
エラー番号c2143とc2059が出てしまいます
何か解決方法はございませんでしょうか?
よろしくお願いします。
No.4ベストアンサー
- 回答日時:
まずは、scanfの仕様をマニュアルなどでよく確認しましょう。
> while( ( ret = fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 ) ) != EOF ){
最初の%[^,]に対して 「char型の配列」s で受けている(正解)のに、2番目以降が 「char型の配列へのポインタ」&n1, &n2 ...で受けています。これらに&は必要ありません。
手元のgccの実装では、配列のアドレスと、その配列へのポインタのアドレスがたまたま同じだったため、「正常」に動作しました。しかし、これがmalloc等で確保した領域への「char型へのポインタ」と、「『char型のポインタ』へのポインタ」だった場合は違うアドレスになり、正常に動作しません。
次にfscanfの取り込み方に関してです。
[^,]とした場合、**改行文字も取り込みの対象になります**。なので、2行目以降のsには、前入力行で取り込まれなかった改行文字が先頭に付くことになります。
また、1行にカンマが4つ無かった場合は、n1,n2,f1で「その行の改行文字まで+次の行の最初のカンマまで」を取り込みます。
sに改行コードを入れないために「fscanf( fp, " %[^\n,]....」と%の前にスペースを置いて、0個以上の空白文字(改行文字も含む)を読み飛ばします。カンマが足りないときのn1,n2,f1の方は[^\n,]として改行も含まない文字に追加します。
最後に、fscanfの戻り値です。
scanf系では、最終的に取り込んだ値の数を返します。
今回の場合、最後の行のあとに、残った改行がsに入るので、ret=1になります。EOFになるのは、その次のループになります。
一応、上の書式変更で「最後の行の後の改行文字をsに取り込む」ということはなくなりますが、ret==5でない時は正常な取り込みではないので、なんらかのエラー処理が必要でしょう。
fscanfは結構やっかいです。
上の改行もそうです。
取り込みエラーでもファイルの読み込み位置が変わらないので、次のループでまたエラーになる、といったこともあります。
1行単位で処理したい場合は、fgetsで1行読み込み→sscanfで処理 というのが常套手段です。
確認に使ったファイルを貼り付けておきましたので、修正前と修正後でどんな風に動いているか、ご自身で確認してみてください
入力:abc.csv
ab1,ef2,ab3,af4,ab5
bb1,bf2,bb3,bf4
cb1,cf2,cb3,cf4,cb5
zb1,zf2,zb3,zf4,zb5
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
char *fname = "abc.csv";
/*char s[100];*/
char *s = (char*)malloc(100); /* 比較のため、mallocでの領域確保 */
char n1[100];
char n2[100];
char f1[100];
char f2[100];
char buf[600]; /* fgets用 */
int ret;
int i=0;
fp = fopen( fname, "r" );
if( fp == NULL ){
printf( "%sファイルが開けません\n", fname );
return -1;
}
printf( "s=%p:&s=%p\nn1=%p:&n1=%p\nn2=%p:&n2=%p\nf1=%p:&f1=%p\nf2~%p:&f1=%p\n",
s, &s, n1, &n1, n2, &n2, f1, &f1, f2, &f2 );
/*↓ 1: 修正前, 0:修正後 */
#if 0
while( ( ret = fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, n1,n2,f1,f2 ) ) != EOF ){
#else
while( fgets( buf,600, fp ) != NULL ) {
ret = sscanf( buf, " %[^,],%[^\n,],%[^\n,],%[^\n,],%s", s, n1,n2,f1,f2 ) ;
#endif
if ( ret != 5) {/* エラー処理 */ }
i ++ ;
printf( "No.%d::\nret=%d\n", i,ret );
printf( "s =%s\nn1=%s\nn2=%s\nf1=%s\nf2=%s\n", s, n1, n2, f1, f2 );
}
fclose( fp );
free(s);
return 0;
}
No.3
- 回答日時:
問題解決に直接結びつくか否かはわかりませんが、
fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 )
で、n1,n2,f1,f2には&をつける必要はないのでは(sに&をつけないのと同じ理由で)
No.2
- 回答日時:
その現象を起こしているソースコードを貼り付けることが、
解決への第一歩です。
この回答への補足
大変失礼致しました
まだ初心者ですのでコードは見よう見まねで打ちました、
初歩的な間違いが多いでしょうがよろしくお願いします。
#include <stdio.h>
int main(void)
{
FILE *fp;
char *fname = "abc.csv";
char s[100];
char n1[100];
char n2[100];
char f1[100];
char f2[100];
int ret;
fp = fopen( fname, "r" );
if( fp == NULL ){
printf( "%sファイルが開けません\n", fname );
return -1;
}
while( ( ret = fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 ) ) != EOF ){
printf( "%s %s %s %s %s", s, n1, n2, f1, f2 );
}
fclose( fp );
return 0;
}
No.1
- 回答日時:
あなたがどのようなプログラムについて話をしているのか分からないので, 「一体どこから沸いて出てくるのでしょうか」と聞かれても「きっとあなたのプログラムから沸いて出てくる」としか言いようがない.
もちろんプログラムが分かればそれに応じてより詳しく答えることができるかもしれない.
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
準・究極の選択
「年収1000万円で一生カレーライス」か 「年収180万円で毎日何でも食べ放題」 あなたはどちらを選びますか?
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
fgetsで2行目から文字化け
C言語・C++・C#
-
C言語で複数列のデータを1列のみ読み込みたい
C言語・C++・C#
-
fgetsなどのときのstdinのバッファを消すには?
C言語・C++・C#
-
-
4
fopne で失敗する原因
C言語・C++・C#
-
5
c言語でのfscanfについて
C言語・C++・C#
-
6
C言語---ファイルに出力したデータをすべて消去する方法
C言語・C++・C#
-
7
カンマ区切りのデータを配列に読み込みたい
C言語・C++・C#
-
8
csvファイルの読み込みで失敗します
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・人生のプチ美学を教えてください!!
- ・10秒目をつむったら…
- ・あなたの習慣について教えてください!!
- ・牛、豚、鶏、どれか一つ食べられなくなるとしたら?
- ・【大喜利】【投稿~9/18】 おとぎ話『桃太郎』の知られざるエピソード
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringからchar*への型変換に...
-
char*を初期化したいのですが
-
C言語にて構造体のメンバがNULL...
-
C言語のintとcharの違いってな...
-
strcpy関数で文字型変数へのポ...
-
char 文字列型 の表現範囲が-12...
-
警告
-
fstream型オブジェクトを関数の...
-
VC++ char[10]へのCString値の代入
-
SetWindowTextについて。
-
C++17で、unsigned char * 配列...
-
36進数
-
文字列の途中から途中までを抽出
-
DWORDとcharの変換
-
エクセルのMID関数は、C言語では?
-
ライブラリ関数
-
ポインタを使用 [数字列を数値...
-
C言語入門者です。今ポインタの...
-
小数点入りの文字列をfloat型に...
-
ASCIIコードへの変換方法
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
CStringからchar*への型変換に...
-
C言語にて構造体のメンバがNULL...
-
fstream型オブジェクトを関数の...
-
小数点入りの文字列をfloat型に...
-
char型にint型の数値を代入する。
-
const char* s1とただのchar s1...
-
new charとnew char[N]の違いは?
-
動的メモリの初期化方法について。
-
エクセルのMID関数は、C言語では?
-
C言語 strstrの実装
-
SetWindowTextについて。
-
char 文字列型 の表現範囲が-12...
-
文字列の途中から途中までを抽出
-
2次元配列の文字"列"の初期化方法
-
DWORDとcharの変換
-
C++17で、unsigned char * 配列...
-
C言語の文字リテラル中の16進文...
-
strcat関数を自作したいです
おすすめ情報