dポイントプレゼントキャンペーン実施中!

sample1.txtというファイルがあり中身が
"JAPAN" = "USA" + "BOLD"
"CHINA" = "UAE" * "KENIA" - "KOREA"
というファイルが存在した場合なのですが.....
これを読み込んでかつ.hファイルに書き込むのですが..
左辺とダブルクオートくくりの文字を抽出するんですけど
とりあえずはいくつか案を考えまして
#include <stdio.h>
int main(int argc, char **argv) {
FILE *fp;
FILE *ft
int c, flag=0;
fp=fopen("sample1.txt","r");
ft =fopen("sample1.h","w");
while ((c=fgetc(fp))!=EOF) {
switch (c) {
case '"': flag=1-flag; if (flag==0) putchar('\n'); break;
case '\n': flag=0;
default: if (flag) putchar(c); break;
}
}
fclose(fp);
fclose(ft);
return 0;
}
これが第一の案なんですけど標準出力は出来ましたが
ダブルクオートくくりの文字しか取れてないんですよ。
.hファイルに書き込むために文字列に入れてから
fprintfを使って出力する方法と左辺の値も一緒にとる方法
どなたかわかりますでしょうか??困っておりまして
ご教授お願いします。

A 回答 (8件)

こんにちは。



質問者さんのやり方とはちょっと違うやり方で考えてみました。

1)まず、入力ファイルも出力ファイルもテキストファイル(末尾の改行で1行と扱う)なので、
  ファイルの読込み、及び書込みも1行単位で扱ったほうが楽だと思いますので、その
  方法を採ってみます。

2)1行分の単語の取り出し方、及び書込み方をを以下の2段階に分けて行います。
  (1) 文字列中の区切り文字('=', '+', '-', '*', '/')を検索して、その文字で切り分けて
    単語を取り出す。
    ※ダブルクォーテーション('"')の検索は後回しにする。
  (2) (1)で取り出した文字列の前後にあるスペース(' ')、タブ('\t')、及びダブルクォーテーション('"')
    を見つけて削除し、その文字列を出力ファイルに書込む。

以上のやり方でサンプルを作ってみましたので参考までに上げてみます。
C++ではなく、C言語のベタで古い手法ですが多少なりとも参考になれば幸いに思います。
また、私の認識不足で質問者さんの意図しているものとは違ったものになっているかも
しれませんので、その際は申し訳ありません。(その際はスルーして下さい。)

お使いの開発環境で上手くビルド及び動作するかどうか判りませんが、宜しければ試して
みて下さい。
(当方では、「Windows98SE+Visual C++ 5.0」の環境でビルド&動作確認しています。)
また、ソース中に間違いなどあれば、ご指摘下されば有り難く思います。
宜しくお願い致します。m(__)m

■サンプルソース
/*
* TxtSplit.c : テキスト分割のサンプルプログラム
*
*【処理概要】
* 入力ファイルから1行ずつ文字列を読込み、区切り文字毎に単語を
* 切出して出力ファイルへ書込みます。
* ・区切り文字は、'=', '+', '-', '*', '/' の5文字としています。
* ・切出した単語の前後にあるスペース' 'とタブ'\t'、及びダブル
*  クォーテーション'"'の文字は削除して出力ファイルに書込みます。
*
*【ファイル形式】
* ◎入力ファイル(既存のテキストファイル)
*  ・1行につき1テキストで区切り文字('=', '+', '-', '*', '/')
*   で単語の区切りとします。
*  ------------------------
*  行位置 テキスト
*   01: JAPAN = "USA" + "BOLD"
*   02: JAPAN2 = USA2 + BOLD2
*   03: "CHINA" = "UAE" * "KENIA" - "KOREA"
*  ------------------------
*  ※単語の前後のスペース' 'とタブ'\t'、及びダブルクォーテー
*   ション'"'は、有っても無くてもどちらの形式でも対応しています。
*
* ◎出力ファイル(新規作成されるテキストファイル)
*  ・上記の入力ファイルだった場合、以下のように出力されます。
*  ------------------------
*  行位置 テキスト
*   01: ANSWER: JAPAN
*   02: ANSWER: USA
*   03: ANSWER: BOLD
*   04: ANSWER: JAPAN2
*   05: ANSWER: USA2
*   06: ANSWER: BOLD2
*   07: ANSWER: CHINA
*   08: ANSWER: UAE
*   09: ANSWER: KENIA
*   10: ANSWER: KOREA
*  ------------------------
*  ※入力した単語の前後の' ','\t','"'は削除して出力します。
*
*【実行時のコマンドライン形式】
* ##>txtsplit [Input File] [Output File]
*  InputFile : 入力ファイル名
*  OutputFile: 出力ファイル名
*
* 注)本プログラムで扱っている文字列は、全てシングルバイトの半角文字列のみを
*   扱っています。
*   使用している文字列関連の関数もシングルバイト用のものを使用しています。
*  ※マルチバイト文字、UNICODE文字 等を扱う場合は適せん対応する文字型の変数、
*   及びそれに対応した文字列関数に変更する必要があります。
*   >例えば、汎用型"tchar.h"に対応したものを使用するなど。。。
*/
#include <stdio.h>
#include <string.h>

/* 定数定義 */
#define BUFMAX 1024 //文字列バッファの最大長

/* プロトタイプ宣言 */
int CheckCmdLine( int argc, char **argv ); //コマンドラインチェック
void DelCRLF( char *strBuf ); //文字列末尾の改行文字削除
void TrimStr( char *strBuf ); //文字列前後の【' ','\t','"'】削除
int SplitStr( char *strInp, char *strOut ); //単語文字列の切出し

/*
* main
*/
int main(int argc, char **argv)
{
int iret = 0; //リターンコード
char *strInpFile; //入力ファイル名
char *strOutFile; //出力ファイル名
FILE *fpInpFile; //入力ファイルポインタ
FILE *fpOutFile; //出力ファイルポインタ
char strLine[BUFMAX+1]; //1行バッファ
char strTemp[BUFMAX+1]; //汎用バッファ

/* コマンドラインのチェック */
if((iret = CheckCmdLine(argc, argv))){
/* エラーコードの補正 */
/* ※パラメータなし or ヘルプ表示オプション時はエラーコードを0にするため */
if(iret > 0) iret--;
return iret;
}

/* 開始メッセージ表示 */
printf("** Convert Start. **\n");

/* ファイル名取得 */
strInpFile = argv[1]; //入力ファイル名
strOutFile = argv[2]; //出力ファイル名

/* 入力ファイルのオープンチェック */
if((fpInpFile = fopen(strInpFile, "r")) == NULL){
iret = 2;
printf("##input file open error.\n");
return iret;
}

/* 出力ファイルのオープンチェック */
if((fpOutFile = fopen(strOutFile, "w")) == NULL){
iret = 3;
printf("##output file open error.\n");
fclose(fpInpFile);
return iret;
}

/* ループ:入力ファイルの終端まで1行毎に読込み */
while(fgets(strLine, BUFMAX, fpInpFile) != NULL)
{
/* 行末の改行文字を削除 */
DelCRLF(strLine);

/* ループ:単語の取り出し&ファイル出力 */
while(SplitStr(strLine, strTemp)) //区切り文字毎に単語を切出す(なくなるまで)
{
fprintf(fpOutFile, "ANSWER: %s\n", strTemp); //切出した文字列をファイルへ出力
}
}

/* ファイルクローズ */
fclose(fpInpFile);
fclose(fpOutFile);

/* 終了メッセージ表示 */
printf("** Convert Complete. **\n");

return 0;
}

/*
* CheckCmdLine : コマンドラインチェック
*
*【引数】
* int argc  : In : コマンドラインのパラメータ数
* char **argv : In : コマンドラインパラメータの配列
*【戻り値】
* int  =0 ... エラーなし
*    =1 ... パラメータなし or ヘルプ表示オプション
*    =2 ... パラメータエラー
*/
int CheckCmdLine( int argc, char **argv )
{
int r1, r2;
int iret = 0;

/* コマンドラインのチェック */
if(argc <= 1){ //パラメータなし?
iret = 1;
}
else { //ヘルプ表示オプション or パラメータエラー?
r1 = strcmp(argv[1], "-?");
r2 = strcmp(argv[1], "/?");
if(r1==0 || r2==0) iret = 1; //ヘルプ表示?
else if(argc < 3) iret = 2; //パラメータエラー?
}

/* エラーメッセージ&ヘルプ表示 */
if(iret != 0){
if(iret != 1){ //パラメータエラー?
printf("##command line error.\n");
}
/* ヘルプ表示 */
printf("[Usage]\n");
printf("TxtSplit [InpFile] [OutFile]\n");
printf("InpFile: Input Text File.\n");
printf("OutFile: Output Text File.\n");
}

return iret;
}

/*
* DelCRLF : 文字列末尾の改行文字削除
*
*【引数】
* char *strBuf : In/Out : 対象文字列
*【戻り値】
* なし
*/
void DelCRLF( char *strBuf )
{
int len;
int pos;
len = strlen( strBuf );
pos = strcspn( strBuf, "\r\n" );
if((pos >= 0) && (pos < len)) strBuf[pos] = 0;
}

/*
* TrimStr : 文字列前後の【' ','\t','"'】の削除
*
*【引数】
* char *strBuf : In/Out : 対象文字列
*【戻り値】
* なし
*/
void TrimStr( char *strBuf )
{
int len;
char *pstr;

/* 先頭の【' ','\t','"'】の削除 */
len = strlen( strBuf );
pstr = &strBuf[0];
while(len > 0)
{
if((*pstr == ' ') || (*pstr == '\t') || (*pstr == '"')){
pstr++; len--;
}
else break;
}
memmove( strBuf, pstr, (sizeof(char) * len) );
strBuf[len] = 0;

/* 末尾の【' ','\t','"'】の削除 */
len = strlen( strBuf );
pstr = &strBuf[len-1];
while(len > 0)
{
if((*pstr == ' ') || (*pstr == '\t') || (*pstr == '"')){
pstr--; len--;
}
else break;
}
strBuf[len] = 0;
}

/*
* SplitStr : 単語文字列の切出し(区切り文字単位)
*
*【引数】
* char *strInp : In/Out : 編集元の文字列
* char *strOut : Out  : 切出し文字列
*【戻り値】
* int  >=0 ... 切出した文字列の長さ
*/
int SplitStr( char *strInp, char *strOut )
{
int len1, len2;
int pos;

/* ループ:入力文字列から切出し文字列が得られるまで */
/* ※切出す毎に入力文字列をその分前方に詰めていく */
while(1){

/* 入力文字列の長さを取得 */
len1 = strlen( strInp );

/* 区切り文字の検索(見つかったインデックスを得る) */
pos = strcspn( strInp, "=+-*/" );

/* 単語の切出し */
if((pos >= 0) && (pos < len1)){ //区切り文字があった時
strncpy( strOut, strInp, pos ); //切出し文字列を得る
strOut[pos] = 0;
len1 -= (pos + 1);
memmove( strInp, &strInp[pos+1], (sizeof(char) * len1) ); //入力文字列を前に詰める
strInp[len1] = 0;
}
else { //区切り文字がなかった時
strcpy( strOut, strInp ); //入力文字列を切出し文字列にコピー
len1 = 0;
strInp[len1] = 0; //入力文字列の長さを0にする
}

/* 切出し文字列の前後の【' ','\t','"'】を削除 */
TrimStr( strOut );

/* 切出し文字列の長さを取得 */
len2 = strlen( strOut );

/* 入力文字列がなくなった時 or 切出し文字列があった時 */
/* はループを抜ける */
if((len1 < 1) || (len2 >= 1)) break;
}

/* 切出し文字列の長さを返す */
return len2;
}

以上です。お役に立てば幸いです。
    • good
    • 0

No.6訂正


>fprintf( fh, %c, (char)c );
ではなく
fprintf( fh, "%c", (char)c );
ですね。出力書式の記述が間違ってました。
失礼しました。
    • good
    • 0

No.4より


>char *v[256];
>v[0] =(char*)c;
>fprintf(fh, %c,v[0]);
>ここの部分はcharがたで領域を確保して配列に文字を代入して
>fprintfで出力ですがいかんせん1文字ずつしかでませんでした....。
間違い。上記は
・「char型のポインタ」の配列v[256]を作成し、
・「cの内容」を「char型ポインタのアドレスにキャスト」しv[0]に代入。
・「char型のポインタ配列」v[0]に格納されている「アドレスの内容」を出力書式%cで出力。
という、正常に動く方が偶然といった内容です。

やるとしたら、
>charがたで領域を確保して
char v[256];
>配列に文字を代入して
v[0] =(char)c;
が正しいけど、一文字ずつ出力するならわざわざ配列に代入する必要ありません。
fprintf( fh, %c, (char)c );
で十分です。

この回答への補足

回答ありがとうございます。
putchar(c);
の部分を
fprintf( fh, %c, (char)c );
にしてみたら
cal_samp.c", 29 行目: % またはそれより前に構文エラーがあります
"cal_samp.c", 38 行目: 前のエラーから回復できません
cc: cal_samp.c に対して、acomp が失敗しました。
*** Error code 2
というエラーが出てしまうのですが.......。
どこがまずいんでしょうか??

補足日時:2008/11/13 16:25
    • good
    • 0

コンソールへの出力は希望する結果が得られているのでしょうか



putchar(c);やputchar('\n');の次にfputc( c, ft );や fputc( '\n', ft );としてみましょう

if文の条件成立時の実行区画を { }でくくるようにしましょう
    • good
    • 0

質問では


"JAPAN" = "USA" + "BOLD"
"CHINA" = "UAE" * "KENIA" - "KOREA"
となっていて, #1 への補足では
JAPAN = "USA" + "BOLD"
となっているんだけど, これは質問文が間違っているということでいいんですか? いや, 明らかに質問文の設定の方が簡単なんだけど....
で各行が
「単語」 = 「ダブルクォートでくくった単語」と「その単語の間の (さしあたり) 無意味な記号列」
という形でいいならおよそ
1. 行の先頭にある「単語」を出力
2. 「=」のあとの最初のダブルクォート (の前) まで読み飛ばす
3. ダブルクォートの中にある単語を出力
という流れになるので, これをそのままプログラムにすれば OK.
まあ,
char *v[256];
v[0] =(char*)c;
fprintf(fh, %c,v[0]);
とかやってる時点で「自分が何をやっているのか全く理解できていない」ことがありありですが.

この回答への補足

早速のご返信ありがとうございます。
おっしゃられるとおり左辺の値はダブルクオートでくくられていません。わたしが最初の質問で間違えてしまいました。訂正してお詫び申し上げます。
それで
char *v[256];
v[0] =(char*)c;
fprintf(fh, %c,v[0]);
ここの部分はcharがたで領域を確保して配列に文字を代入して
fprintfで出力ですがいかんせん1文字ずつしかでませんでした....。
さしあたり差し支えなければTacosan様のお考えになったフローを
ソースコードにしていただければ参考になるのでありがたいのですが。。。。

補足日時:2008/11/13 12:04
    • good
    • 0

putcharでコンソールに出力している部分を変更したいだけなのでしょうか?



charをつかってファイル出力するライブラリー関数を探してみましょう
入力はfgetcなのですし、コンソールへの出力がputcharなのですからほんのちょっと考えれば予想が付きますよね

この回答への補足

ご返信ありがとうございます。
調べまして
putchar(c);のところを
まずchar型で宣言して
char *v[256];

v[0] =(char*)c;
fprintf(fh, %c,v[0]);
にしたところ.hファイルに書き込まれる内容が
J
A
P
A
N
U
S
A




・こんな感じになっちゃうんですけど。。。。。
どうしたらいいでしょうか??
私といたしましては左辺の値とダブルクオートで区切られている文字を
抽出したい方向性でいるのですが......。
すなわちJAPAN = "USA" + "BOLD"の場合
JAPAN
USA
BOLD
の形で出力させる方向性で考えております。
ここが分からないんですよね??????

補足日時:2008/11/13 10:46
    • good
    • 0

うん, #1 でも書かれているけど「どのような出力がほしいのか」がわからない以上, どうすればいいのか全く見当もつきません.


ついでにいうと
・flag=1-flag; という文は何をしたいのか. 論理的に反転させたいなら flag = ! flag; であるべき.
・flag という変数名は何を表すか全くわからないのでやめること. フラッグを使う必要があるかどうかわからないけど, 使うなら例えば in_string のようにより意味のわかる変数名にすること.
くらいは気をつけた方がいいと思う.
    • good
    • 0

sample1.h ファイルの中身をどうしたいのか補足にどうぞ。

この回答への補足

ご返信ありがとうございます。
結論的にいいますと......
JAPAN = "USA" + "BOLD"  ←左辺はダブルクオートでくくられていません。
上記のファイルを読み込みsample.hファイルに
正確にいうと
ANSER: JAPAN
ANSER: USA
ANSER: BOLD
といった形でfprintfを使って出したいと思っています。
そのために左辺の値とダブルクオートでくくられた値を
うまくとらなければいけないのですが......
なかなかうまくいきません。ご教授お願いします。

補足日時:2008/11/13 10:57
    • good
    • 0

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