Thinkers'Studio
JavaとC言語の自習ツール
fscanf で csvファイルから入力するには

 書式つきのファイルから入力するときは、fscanf関数をよく使います。
 ただし、csvファイルから %s で読むときは、少し工夫が要ります。 たとえば、次の読み込みは上手くいきません。

 例 「1123,NOTEPC,59800」 カンマ区切りデータ、2つ目のレコードは文字列
    fscanf( fp, "%d,%s,%d", &shcd, name, &price );  //商品コード,商品名,価格
   正しく入力できません(shcd しか読めません)。

%s 変換の入力の終了

 %s 変換では、空白文字(半角スペーやタブや改行、ほかに復帰、垂直タブ、改ページ)が来ると、読み込みを終わります。
 ,(カンマ)は、空白文字ではないので入力の区切りとならず、文字列の一部として読み込まれてしまいます。
 もしも、文字列データが 1種類で、必ず行の最後にあるなら(上の例では、商品名と価格のデータ順を入れ替えたとき)、読み込みに成功します。 なぜかというと、文字列データのうしろにカンマがありません。そして改行で %s の入力が終わるからです。

 次のプログラムのようにすると、順番を入れ替えなくても fscanfcsvファイルから入力できます。

fscanfcsvファイルを入力するプログラム例 】
#include <stdio.h>
#include <stdlib.h>

main()
{
    FILE *fp;
    int shcd, price;
    char name[24];

    if( (fp = fopen( "data.csv", "r")) == NULL ) {
        printf( "入力ファイルがオープンできません\n" );
        exit(1);
    }

    while( fscanf( fp, "%d,%[^,],%d", &shcd, name, &price ) == 3 ) {
        printf( "%d, %s, %d\n", shcd, name, price );
    }
    fclose( fp );
}
 %[^,]
  と書くと , が現われるまで文字列として読み込みます。少し例を示します。
指定例  意味                例
[,]      カンマの並び          ",,,ABC" ⇒ ",,,"
[0-9]    数字の並び            "001.321" ⇒ "001"(1ではありません)
[a-z]    英小文字の並び        "yes, I do" ⇒ "yes"
[quick]  いずれかの文字の並び  "cuiqqkly" ⇒ "cuiqqk"
指定の前に ^(キャレット)を付けると否定の意味になります。
[^,]     カンマ以外の並び      "AB,CD" ⇒ "AB"(カンマが現われるまで読み込むことになる)
[^0-9]   数字以外の並び        "wid24.5" ⇒ "wid"(数字が現われるまで読み込む)
(今回のクイズです)
 上のプログラムの fscanf 入力書式を次のように変えたとします。
    while( fscanf( fp, "%d,%[A-Z],%d", &shcd, name, &price ) == 3 ) {
 その場合、データ 「1123,NOTEPC,59800」 の入力に成功するでしょうか? 2択です。
   (1) NOTEPC は A-Z という文字列に一致しないから失敗する(×)
   (2) NOTEPC の文字はすべて A-Z の大文字アルファベットだから成功する(○)
   (答えは、次回のC言語の Tips で ・・・)

[ 関連記事 ] fgets と sscanf で ファイルから入力, 入力時に不要データをスキップ

前回のクイズの答え: (前回の問題を見る
 switch の default 処理で、return -1 の前に wareki が整数で読めるか試す処理を追加します。
    default:
        // %dで読めれば西暦指定とみなしそれを返す、不可ならエラー
        if( sscanf( wareki, "%d", &year ) == 1 ) return year;
        return -1;