プロが教える店舗&オフィスのセキュリティ対策術

csvファイルをfscanfで読み込もうとしているのですが
どうしてもおかしな文字が混じってしまいます

例えばcsvファイルのデータが

abc,efg
となっているとします

これを読み込みprintfで表示すると
abc"" efg""

というように表示されてしまいます

csvファイルを普通に開いてもこのような文字はありません
一体どこから沸いて出てくるのでしょうか?

%[^]を使って不要な文字を読み込まないように
%[^"]と記述しましたが
エラー番号c2143とc2059が出てしまいます

何か解決方法はございませんでしょうか?
よろしくお願いします。

A 回答 (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;
}
    • good
    • 1
この回答へのお礼

長文に渡る丁寧なご回答に感謝します
早速実行して自分好みに色々手を加え、結果に大満足です
本当にありがとうございました。

お礼日時:2010/02/27 17:58

問題解決に直接結びつくか否かはわかりませんが、



fscanf( fp, "%[^,],%[^,],%[^,],%[^,],%s", s, &n1, &n2, &f1, &f2 )

で、n1,n2,f1,f2には&をつける必要はないのでは(sに&をつけないのと同じ理由で)
    • good
    • 0
この回答へのお礼

全くその通りですね!
貴重なご指摘に感謝します!

お礼日時:2010/02/27 17:56

その現象を起こしているソースコードを貼り付けることが、


解決への第一歩です。

この回答への補足

大変失礼致しました
まだ初心者ですのでコードは見よう見まねで打ちました、
初歩的な間違いが多いでしょうがよろしくお願いします。

#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;
}

補足日時:2010/02/27 09:26
    • good
    • 0

あなたがどのようなプログラムについて話をしているのか分からないので, 「一体どこから沸いて出てくるのでしょうか」と聞かれても「きっとあなたのプログラムから沸いて出てくる」としか言いようがない.


もちろんプログラムが分かればそれに応じてより詳しく答えることができるかもしれない.
    • good
    • 0

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

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A