strtokにて分解した文字を各変数に格納する場合
char *p;
FILE *fp;
char buf[1000];
if((fp = fopen("○","r"))==NULL){
return 0;
}
if(!fgets(buf,1000,fp)) return 0;
strcpy(p, buf);
number = strtok(p,",");
class_type = strtok(NULL,",");
name = strtok(NULL,",");
subject = strtok(NULL,",");
と一行の文字列を各変数に格納しています。
ファイルの一行は以下のような形式になっています。
1,A,山田,数学//番号,クラスタイプ,名前,得意教科
これで各値は変数に格納できています。
しかし
このファイルはCSVファイルなのですが、空の欄があると
1,A,,数学というデータがbuf内に入っています。
この場合
number→1
class_type→A
name→数学
と空欄の箇所が飛ばされてしまっています。
改善する方法がわからないのですが
strtokを使わない方がいいのでしょうか?
A 回答 (5件)
- 最新から表示
- 回答順に表示
No.5
- 回答日時:
があっという間に締め切られたので、こちらに回答。
>\の所を_に変更したらバグりませんでした。ありがとうござました。
別の漢字でバグるようになっただけで、何の解決になってません。
「表」の代わりに「農」とか「廟」とか書いたらバグります。
No.4
- 回答日時:
>1,A,,数学で試したら
>class_typeにA,,数学が入ってて
>nameとsubjectには何も入ってませんでした。
それは
if(!fgets(buf,1000,fp)) return 0;
のあとに
if (buf[strlen(buf) - 1] == '\n') buf[strlen(buf) - 1] = '\0';
p = (char *)malloc(strlen(buf) + 1);
ってやってないからじゃないでしょうか?
pの初期化とメモリ確保は何処行っちゃったんですか?
http://okwave.jp/qa5087561.html
のANo.6で提示した例題は「どこかが1行でも欠けたら動かない」ので、変に端折ったり処理を削っちゃダメです。
因みに、この質問のANo.2を投稿する前に「一部の項目を省略した場合の全パターン」を読み込ませて、正しく動いたのを検証・確認してから投稿してます。
正しく動かなかったのは「質問者さんが勝手に改変。省略して、動く物を動かなくしちゃったから」です。
因みに、当方は
1,A,田中,社会
,B,鈴木,音楽
3,,佐藤,国語
,,山田,算数
5,A,,社会
,B,,音楽
7,,,国語
,,,算数
9,A,田中,
,B,鈴木,
11,,佐藤,
,,山田,
13,A,,
,B,,
15,,,
,,,
と言う「すべての省略パターンが出現するcsvファイル」を読ませて、正しく動いているのを確認してから投稿しています。
質問者さんが勝手に改変し、動いている状態の物を動かない状態にされて「動きません」って言われても困ります。自分が行った改変は自分で責任取って下さい。そこまで面倒見切れません。
この回答への補足
問題文はstrtokを使っている流れを軽く載せただけで
strtokってこういうのは無理なの?という話です。
コメントでこういう風に修正しようと言われたので
質問文の方はあまり気にしていませんでした。本文はちゃんと
省略せずなっていると思いますがそこまで検証していただいているなら
どこかミスがあるのでしょう。見直してみます
No.2
- 回答日時:
strtokは「,,,」のような「連続したセパレータ文字」を「1つの固まり」として処理するので「,」も「,,」も「,,,」も区別出来ません。
前回の回答では「空欄は無い筈」という前提でサンプルを作成して回答しました。
空欄が存在する可能性があるなら「自前で文字列の終端記号の'\0'を埋めながら「,」の次の位置まで進めていく」と言う処理が必要です。
例えば、
strcpy(p, buf);
number = strtok(p,",");
class_type = strtok(NULL,",");
name = strtok(NULL,",");
subject = strtok(NULL,",");
を
strcpy(p,buf);
number = p;
if (p[strcspn(p,",")] == ',') {
p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/
p += strlen(p) + 1; /*pを「,の次」に進める*/
} else {
p += strlen(p); /*pより後ろに「,」が無いけどエラーにしない*/
}
class_type = p;
if (p[strcspn(p,",")] == ',') {
p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/
p += strlen(p) + 1; /*pを「,の次」に進める*/
} else {
p += strlen(p); /*pより後ろに「,」が無いけどエラーにしない*/
}
name = p;
if (p[strcspn(p,",")] == ',') {
p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/
p += strlen(p) + 1; /*pを「,の次」に進める*/
} else {
p += strlen(p); /*pより後ろに「,」が無いけどエラーにしない*/
}
subject = p;
のように修正します。
こうすると、空欄があった場合、各変数はNULLにはならず「長さ0の文字列」になります。
従って、前回の回答の
if(!DataPtr->class_type || !DataPtr->name || !DataPtr->subject) {/*カンマで4項目に区切れない*/
printf("項目が足りません。");
return -1;
}
の部分は無意味になります。これらがNULLになる事はありませんから。
なお、上記の処理では
1,A,山田
や
1,A
などのように「カンマが3つ無い」と言う場合にエラーになりませんから、カンマが足りない時にエラーで中断する場合は、判定方法を変える必要があります。
もし
1,,山田,数学
や
1,A,山田,
は「カンマが3つあるからOK」にして
1,A,山田
は「カンマが3つないからNG」にするのなら
strcpy(p,buf);
number = p;
if (p[strcspn(p,",")] == ',') {
p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/
p += strlen(p) + 1; /*pを「,の次」に進める*/
} else {
printf("項目が足りません。");/*pより後ろに「,」が無いのでエラー*/
return -1;
}
class_type = p;
if (p[strcspn(p,",")] == ',') {
p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/
p += strlen(p) + 1; /*pを「,の次」に進める*/
} else {
printf("項目が足りません。");/*pより後ろに「,」が無いのでエラー*/
return -1;
}
name = p;
if (p[strcspn(p,",")] == ',') {
p[strcspn(p,",")] = '\0'; /*「,」の位置に終端記号を置く*/
p += strlen(p) + 1; /*pを「,の次」に進める*/
} else {
printf("項目が足りません。");/*pより後ろに「,」が無いのでエラー*/
return -1;
}
subject = p;
というように変更します。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- Visual Basic(VBA) フォルダの場所を可変にしたいです(マクロ) 4 2023/05/11 10:00
- Visual Basic(VBA) 複数csvを横に追加していくマクロについて 2 2023/04/25 09:19
- Excel(エクセル) 2つのVBAを一緒にしたら機能しなくなりました(エクセル) 7 2022/06/02 12:41
- C言語・C++・C# #include <stdio.h>int main(void) { int buf[100] = 6 2022/11/01 22:45
- C言語・C++・C# C言語のバイナリファイルに関する質問 8 2022/06/24 07:20
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
プログラミングの授業の課題です
-
Cでファイルの行数をカウントす...
-
#defineが使用するメモリ領域に...
-
printf による16進表示について
-
構造体メンバの初期化
-
[C言語 Windows] Visual Cでの...
-
空白を含んだ文字列がうまく格...
-
矢印キーを押下してコンソール...
-
C言語で複数列のデータを1列の...
-
タイムカードのシステムを作り...
-
C言語のプログラムで、途中で止...
-
[C]セグメンテーションエラー:...
-
終了条件Ctrl+zについて,結果表...
-
C言語でのCSVファイルの読み出...
-
C++で指定文字列のカウント方法...
-
数字以外が入力されたらエラー...
-
「指定されたキャストは有効で...
-
fgetsなどのときのstdinのバッ...
-
マイナスからプラスへ転じた時...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
Enterキーを押されたら次の処理...
-
C言語で複数列のデータを1列の...
-
#defineが使用するメモリ領域に...
-
printf による16進表示について
-
空白を含んだ文字列がうまく格...
-
C言語のプログラムで、途中で止...
-
プログラミングの授業の課題です
-
char型2つを結合し、short型に...
-
C言語でのCSVファイルの読み出...
-
矢印キーを押下してコンソール...
-
【C言語】全角文字の配列を、全...
-
エラーについて質問です。
-
リストの作成と出力(C言語)
-
バイナリファイル(画像)のよみ...
-
[C]セグメンテーションエラー:...
-
WinInetのInternetOpenUrl関数...
-
VC++でSQLへSELECT文を送ったの...
-
受信データから必要な部分のみ...
-
c言語で文書を読み込み、単語の...
-
reallocでエラー
おすすめ情報