ページ 1 / 1
繰り返し出てくるものから
Posted: 2015年6月19日(金) 12:19
by mo-fu
いつも楽しく見ております。
今回も少し知恵を貸していただきたいと思っています。
C言語/ windows7 /Microsoft Visual C++ 2010 Expressを用いています。
例えば
テキストファイルに
A = [数値1]
A = [数値2]
A = [数値3]
中略
A = [数値N]
File End.
とあり、私はそこから 数値Nだけ(最後に現れる数値)だけを取り出したいと思っています。Nは定数ではなく、ファイルによってさまざまです。実際はこんなにシンプルではなくこれ以外の情報が大量に書き込まれたテキストですが、「A =」という文字列はその他の行には現れず、特異的な文字列です。
そのテキストファイルを一行ずつ読み 「A =」という文字列を見つけたときだけ、以下の手順を踏んで
コード:
if(strstr(str,key)){//「A =」がある行を探す
tok = strtok( str, s1 );//その行をバックスペースで区切る
while( tok != NULL ){
tokcounter ++;
if(tokcounter == 3){//区切ったものから数値を選ぶ
LastTok = tok;
}
}
}
*LastTok に数値N(実際には文字列として扱ってますが)を収納しています。
このあとファイルをケツまで読み終わったら、LastTokをoutputファイルに書き出すのですが、なぜかそのとき 「File End.」の文字列が書き出されてきます。
この行に「A =」は現れませんし、「A =」が現れたときしかLastTokに文字列を収納(引き渡し)してないはずなのに!と自分では思うのですが、結果は正直なものでこの現象から抜け出せません。
具体的なファイルやプログラムの全体像を載せることが出来ないので、伝わりづらいかもしれませんが、何か打開策があればよろしくお願いします。
Re: 繰り返し出てくるものから
Posted: 2015年6月19日(金) 13:18
by Tatu
このような感じですか?
コード(1つ下のみけCATさんの投稿も確認してください)
► スポイラーを表示
コード:
#include <stdio.h>
#include <string.h>
int main(void){
char str[1024];
char *pointer=NULL;
int data;
FILE *fp = fopen("test.txt", "r");
if (fp != NULL){
//1行ずつ最後の行まで処理する
while (fgets(str, sizeof(str), fp)!=NULL){
//「A =」が見つかる行のみ処理する
if (strstr(str, "A =") != NULL){
//整数を取り出して表示する(注:str+3は「A =」が3バイトだから)
sscanf(str+3,"%d", &data);
printf("%d\n", data);
}
}
//最後のデータは取り出したい
printf("最後のデータは%dでした\n", data);
fclose(fp);
}
return 0;
}
テストファイル(test.txt)
► スポイラーを表示
コード:
yokuwakaranai
A = 1
A = 2
A = 2
A = 3
A = 3
A = 3
A = 4
A = 4
A = 4
A = 4
A = 5
A = 5
A = 5
A = 5
A = 5
owaridattesa
実行結果
► スポイラーを表示
コード:
1
2
2
3
3
3
4
4
4
4
5
5
5
5
5
最後のデータは5でした
続行するには何かキーを押してください . . .
Re: 繰り返し出てくるものから
Posted: 2015年6月19日(金) 13:49
by みけCAT
Tatu さんが書きました:コード:
if (strstr(str, "A =") != NULL){
//整数を取り出して表示する(注:str+3は「A =」が3バイトだから)
sscanf(str+3,"%d", &data);
printf("%d\n", data);
}
せっかく検索したので、その結果を利用した方がいいと思います。
コード:
char* str2;
if ((str2 = strstr(str, "A =")) != NULL){
//整数を取り出して表示する(注:str2+3は「A =」が3バイトだから)
sscanf(str2+3,"%d", &data);
printf("%d\n", data);
}
Re: 繰り返し出てくるものから
Posted: 2015年6月19日(金) 13:58
by Tatu
LastTokが思った通りの内容にならない理由について
LastTokはtokと同じ場所を参照するようになっています。
tokはstrtok()が返す場所を参照するようになっています。
何らかの理由(strstr()でしょうか?)でstrtok()が返す場所が書き換えられると
LastTokが参照している場所のデータは書き換えられた後のデータとなります。
文字型変数のポインタLastTokにtokを代入するのではなく、
文字列LastTokにtokが指している文字列をコピーするようにしたらどうなりますか?
>>みけCATさん
確かに「A =」の後のデータが欲しいのだということを示すために検索した結果を利用したほうがいいですね。
Re: 繰り返し出てくるものから
Posted: 2015年6月19日(金) 17:16
by mo-fu
Tatu様、みけCAT様
早急な返信ありがとうございます。やはり困ったときの神頼みだなと思います。(いけないことですが。)
>>Tatu様
sscanfを使う方法もやってみたのですが、なぜかうまくいかなくて。でも、あれ?Tatuさんのだと出来てる…と思って再確認してみたら、渡している文字列が間違っていたようです。笑 もう一度試してみます。
Tatu さんが書きました:LastTokはtokと同じ場所を参照するようになっています。
tokはstrtok()が返す場所を参照するようになっています。
何らかの理由(strstr()でしょうか?)でstrtok()が返す場所が書き換えられると
LastTokが参照している場所のデータは書き換えられた後のデータとなります。
自分では 「A =」を見つけて、さらに特定の場所を見つけたときだけ、LastTokにTokと同じ場所を参照させているつもりでいましたが、そうはなっていなかったのですね。精進いたします。
解決後、また解決タグを付けに来ます。取り急ぎお礼まで。
Re: 繰り返し出てくるものから
Posted: 2015年6月20日(土) 00:19
by ISLe()
mo-fu さんが書きました:自分では 「A =」を見つけて、さらに特定の場所を見つけたときだけ、LastTokにTokと同じ場所を参照させているつもりでいましたが、そうはなっていなかったのですね。精進いたします。
そこは間違ってないです。
LastTokやTokの指している場所が、ファイルから読み込んだデータで上書きされるので、最終的に最後に読み込んだデータを指している状態になります。
質問の時点からいちばん手間がかからないのは
LastTokを(ポインタではなく)配列で宣言して、Tokから文字列をコピーしてやる方法です。
Re: 繰り返し出てくるものから
Posted: 2015年6月23日(火) 02:13
by かずま
mo-fu さんが書きました:sscanfを使う方法もやってみたのですが、なぜかうまくいかなくて。
コード:
#include <stdio.h>
int main(void)
{
int data, lastData = 0;
char str[1024];
FILE *fp = fopen("foo.txt", "r");
if (!fp) return 1;
while (fgets(str, sizeof str, fp))
if (sscanf(str, " A =%d", &data) == 1)
printf("%d\n", lastData = data);
fclose(fp);
printf("last data = %d\n", lastData);
return 0;
}
foo.txt
コード:
A = 123
B = 45
C = 6789
A = 987
B = 65
C = 4321
A = 753
B = 246
file End.
実行結果
コード:
123
987
753
last data = 753
Re: 繰り返し出てくるものから
Posted: 2015年6月23日(火) 13:24
by mo-fu
ISLe() 様 かずま様
返信ありがとうございます。
>>ISLe() 様
ISLe() さんが書きました:LastTokやTokの指している場所が、ファイルから読み込んだデータで上書きされるので、最終的に最後に読み込んだデータを指している状態になります。
tok・Lasttokに場所を渡すのはif文の中だけなので、tokもはLasttokも私が設けた条件の時に渡した場所をずっと覚えていてくれると思っていましたが、そうではないみたいですね。素人が下手にポインタを使おうとするとなかなか難しいです。
>>かずま様
ありがとうございます。実は簡単のために[A =]と表現したのですが、実際は[英文 = 数値 英文] とサイズ・内容共に出現するたびに変化していて、sscanfは上手い手が思いつかない時の最終手段かな と思ってました。 でもこういう教科書に載っているような小さなプログラムを短時間でエラーなく書けることが大切なんだなぁと実感させられました。
皆々様方ありがとうございました!無事動くものが完成しましたので、解決タグをつけに参りました。
また困ったら、神頼みしに来ますね!(笑) ありがとうございました。
Re: 繰り返し出てくるものから
Posted: 2015年6月23日(火) 18:05
by ISLe()
mo-fu さんが書きました:tok・Lasttokに場所を渡すのはif文の中だけなので、tokもはLasttokも私が設けた条件の時に渡した場所をずっと覚えていてくれると思っていましたが、そうではないみたいですね。素人が下手にポインタを使おうとするとなかなか難しいです。
『あそこの角にあった』コンビニがいつのまにかコンビニでなくなってたというようなふつうにあること(概念)です。
そこにコンビニがあったことを記録しておくために写真を撮っておいたりする(コピーを作っておく)というのも自然なことです。
コンビニは簡単に無くなるものなのに、多くのひとがそこにあるものが恒久であるという思い込みを持ちます。
それと同様の問題であって、ポインタ自体は難しいものではありません。