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

現在C言語でプログラム開発しています。
文字列が並んだテキストファイルから特定の部分のみを抽出したいのですが、うまくいきません。
お力を貸していただけないでしょうか。

テキストファイルの構造はこんな感じです。

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー
文字列

文字列

文字列badresult=*****文字列badresult=*****文字列badresult=*****文字列result=*****

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

これが10セット程記述されたファイルです。
ここから全てのbadresultの数値とresultの数値を抽出したいのです。
私が現段階で作成したプログラムがこちらです。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXLINE 2084

int main(void){
FILE *fp;
char line[MAXLINE];
char s1[]="badresult";
char s2[]="result=";
char *r;


if ((fp = fopen( "テキストファイルへのダイレクトパス", "r" )) == NULL){
printf("エラーメッセージB\n");
exit(1);
}


while (fgets(line, MAXLINE, fp) != NULL){
if(strstr(line,s1)!=NULL){
printf("%.27s",strstr(line, s1),"\n");
printf(" ");

printf(strstr(line, s2));
}

}
}

ですがこれだと1行に全てのbadresultが含まれているため、結果は
-----------------------------
badresult=***** result=******
-----------------------------

とbadresultは1つしか出てきません。
strstrのポインタをどうにかできないかと考えたのですが、
私のC言語の知識も浅いためなかなかうまくできません。
Cプログラミングに精通している方、どうか改善策を教えていただけないでしょうか。
できればなるべく簡単な方法ですと助かります。

A 回答 (7件)

すでにツッコミ入ってるので気付いておられるかもですが、



> 私のやり方が悪いのでしょうか?

です。私のは最大でも 27 文字分しか一度に足しません。単純に r += 27 としなかったのは、行末とフォーマットの曖昧さを考えての保険です。

> 例が悪かったですね。実際のファイルですとbadresultはSCT、
> resultはACTというものなので一致はしないんです。

伏せ字にするのはかまいませんが、文字数や字種などは「そのまま」を提示しないと、話になりません。もっと融通のきくスクリプト言語とかならそうでもないですけどね。

この回答への補足

回答ありがとうございます。参考になりました。
おかげで結果が汚いのですが、うまくいきました。

補足日時:2011/12/15 15:28
    • good
    • 0

紛糾?していますが、あまり気になさらないでください。


皆さんが指摘されているように、文字列の処理は結構大変なのです。いろいろなケースを考えるとstrstrではなかなか対応できないことがほとんどなのです。

正規表現の例を少し書きます。
badresult=123
のように整数だと簡単ですが、-123.4のように-が入ったり小数になったり、また文字数も一定せずなどいろいろな場合があります。
文字数が決まっているのなら文字数決めうちということもあり得るのですが、現実的にはどうなんでしょうか。
例えば
badresult=123 他の文字badresult =-345関係ない文字badresult= +678.87分からん文字列 result= -0.900
という文字列だったとします。文字列をlineに入れたとして
Rubyの例ですが、(Perlでも多分同じようにできるはずです)
line.scan(/(badresult|result) *= *([+-]?\d+(?:\.\d*)?)/)
でかなりの自由度で取り出すことができます。
実行した結果は
[["badresult", "123"], ["badresult", "-345"], ["badresult", "+678.87"], ["result", "-0.900"]]
です。
badresult、resultの別と数値が取り出されます。
/(badresult|result) *= *([+-]?\d+(?:\.\d*)?)/
が正規表現の部分です。

Cの定番の正規表現ライブラリは分かりませんが、私の使っているソフトウエアにはよく「鬼車」が使われています。
Cはほとんど使いませんので、使い勝手などはわかりません。

折衷案として、CからRubyやPerlをパイプで呼び出すということもできます。
上に書いたような結果を受け取り(もっと簡単には数字の部分だけでも)、それをCで処理するのはいかがでしょうか?
もし、質問さんがプロのプログラマを目指しているのでしたら、Cを苦労してでも習得されることをお勧めしますが、
そうでないのでしたら、いろいろなプログラム言語を経験され、自分の仕事に合うものを見つけられるのが良いと思います。

私を含めてまわりにプロのプログラマを目指す人はいないので、(みなさん仕事のプロを目指しています)必要に応じてRubyを勧めています。

この回答への補足

回答ありがとうございます。やはりC言語で行うのは難しいみたいですね。みなさんが薦めてくださっているperlも試してみたいと思います。

補足日時:2011/12/15 15:31
    • good
    • 0

具体的と言われても、そもそもが具体的でないので無理です。


今の例にあったものは書けますが、これが内容が違った場合(実際に違うようですが)にs1,s2を変更するだけか、というと、そうとは限りません。作り方やデータによっては正常に動作しません。

次の場所から探すには、前回の続きから探せばいいわけです。
#2の回答では %.27sで表示している→27文字後ろから次を検索すればいい
という考えで27加えています。
あなたの#2の補足にあるのは、「残りの文字数全部」をstrlenで加えてしまっています。つまり、文字列の終わりへ移動するので、見付かるわけがありません。

次がどこからがいいか、は、今の情報ではわかりません。
一つのアイディアは、検索につかったs1の文字数だけずらすこと、です。


正直、Cで文字列操作するのって、面倒です。(少なくとも、私は)
どうしてもCでやるにしても、先にPerlかなんかで必要なところだけ抜きだして、Cではscanfとかでの単純な読み出し、とかするのが楽じゃないですか?

この回答への補足

ありがとうございます。Perlがやりやすいという話は知人からもされました。これを機に勉強してみたいと思います。

補足日時:2011/12/15 15:30
    • good
    • 0

#2 の補足に書かれているコードなんだけど, 一番中の for で


r += strlen(r)
としているのは何を期待してのことでしょうか?

この回答への補足

strstrで読み取った文字ポインタを移動できないかと考えたのですが・・・。改善点があれば教えてください。お願いします。

補足日時:2011/12/14 19:11
    • good
    • 1

badresult=*****文字列badresult=*****文字列badresult=*****文字列result=*****


の部分は、例えば
badresult=123badresult=345badresult=678result=900
のように数字しか無いのか
badresult=123関係ない文字列badresult=345
のように、関係ない文字列も入っているのでしょうか?
いずれにしても、lineに読み込んで、badresult=123を取り出した後に、
残りのbadresult=345badresult=678result=900から探さないと駄目ですね。

ところで、C言語でないと駄目なのでしょうか?
正規表現が簡単に使えるRubyなどだと数行で書けますが。
Cでも正規表現が使えるライブラリを使えば簡単なはずですが。

この回答への補足

回答ありがとうございます。
badresult=123関係ない文字列badresult=345
のように、関係ない文字列が間に入っています。

できればC言語で行いたいのです。
ライブラリについて少し調べてみます。

補足日時:2011/12/14 19:10
    • good
    • 0

> とbadresultは1つしか出てきません。


そりゃ繰替えしもしないで、二つ以上でたら困るし

> badresult=***** result=******
この二番目の result= の方だけど、

> printf(strstr(line, s2));
これだと最初の badresult= の result= から後ろが一致してない?

決め打ちで %.27s も気になるし、ファイルフォーマットがどうなってるかにも寄るけど、もう少し条件整理したほうがいいと思う。

ちなみに strstr() の件は例えばこんなの
for (r = line; r = strstr(r, s1); r += len){
if ((len = strlen(r)) > 27)
len = 27;
printf("%.*s ", len, r);
}

この回答への補足

回答ありがとうございます。
例が悪かったですね。実際のファイルですとbadresultはSCT、
resultはACTというものなので一致はしないんです。

教えてくださったものを改良して

while (fgets(line, MAXLINE, fp) != NULL){
if(strstr(line, s1)!=NULL){
for (r = line ;r = strstr(r, s1); r += strlen(r) ){
printf("%.27s,\n",strstr(r, s1));

}
}

}

というようにしてみたのですが、結果は変わりませんでした。
私のやり方が悪いのでしょうか?

補足日時:2011/12/14 16:44
    • good
    • 0

strstrのマニュアルを読んでください。


戻り値をうまく使えば、続きから検索しなおすことができます

この回答への補足

ありがとうございます。
その方法で取り組んだのですが、うまくいかず困っていたので質問させていただいたのです。
具体的なソースなど記述していただけるとなおありがたいです。

補足日時:2011/12/14 13:17
    • good
    • 0

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