• ベストアンサー

VisualC++

現在VisualC++6.0を使いC++言語を勉強しています。 あるテキストファイルを読み込んでそのファイルの中の文字列を 数字と英文字を切り分けて一行ずつ表示するプログラムを作りたいのですがどうやって切り分ければよいのかわかりません。(テキストファイルは英文字と数字のみで構成されていることを前提) 一行ずつ表示するのはfgets関数を使えばいいと思うのですが 切り分けの作業がどうも上手いこといきません。 一文字ずつ読み込んでその文字がA~Zの中にあれば 切り分ければと思い試してるのですが上手いこといきません。。 教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • yama5140
  • ベストアンサー率54% (136/250)
回答No.9

>現在VisualC++6.0を使いC++言語を勉強しています。  No.6 さんの「回答」とおりに(C++ではなくCで)コード化してみました。  (BorlandC++5.6.4)  CとC++では、No.4 さんのソースから判るとおり、大きく違います。  Cではこんなか?程度に見て頂ければ・・。 >一行ずつ表示するのはfgets関数を使えばいいと思うのですが  typo ではない(?失礼)として、「ファイル入力」部分もコメントにして記述してみました。  ・現状では、1D2FF4CFS56HAS ? DAFD334F\n を「仕様」に沿って区切ります( \n は「レコード」模倣)。  ・fgets 関数を習得( No.8 さんの「C言語 ですよね?」として)しましたら、コメントをはずすし、ファイルからの処理をお試し下さい。 #include <stdio.h> #include <ctype.h> #include <stdlib.h> int  MojiSyuHantei( char cc ) {   if( isdigit( cc ) )  return( 1 );   if( isupper( cc ) )  return( 2 );   return( 0 ); } void  main() {   int  i = 1;    // while 文で2文字目から   int  iMaeMojiSyu, iMojiSyu;   char  cBuf[ 512 ] = "1D2FF4CFS56HAS ? DAFD334F\n"; //  FILE  *fp; //  fp = fopen( "TEST.TXT", "r" ); //  if( NULL == fp )  exit( 0 ); //  while( NULL != fgets( cBuf, 512, fp ) ){  // 1行読み込み     printf( "%s", cBuf );     printf( "(%c", cBuf[ 0 ] );  // 先頭の ( と1文字目     iMaeMojiSyu = MojiSyuHantei( cBuf[ 0 ] );     while( '\n' != cBuf[ i ] ){  // 2文字目から       iMojiSyu = MojiSyuHantei( cBuf[ i ] );       if( iMaeMojiSyu != iMojiSyu ){  // 文字種異なる         printf( "),(" );  // 区切り         iMaeMojiSyu = iMojiSyu;       }       printf( "%c", cBuf[ i++ ] );  // 1文字ずつ出力     }     printf( ")\n" );  // 行末の ) //  } //  fclose( fp ); } 注:インデントに全角空白を用いています。タブに一括変換して下さい。

その他の回答 (10)

回答No.11

#include <stdio.h> #include <ctype.h> int isborder(int c1, int c2) { return (isdigit(c1) && isalpha(c2)) || (isdigit(c2) && isalpha(c1)); } char *fsplit(char *str, const char punct, FILE *fp) { int c1, c2; if((c1 = fgetc(fp)) == EOF) return NULL; while(c1 != EOF && c1 != '\n'){ c2 = fgetc(fp); *str ++ = c1; if(isborder(c1, c2)) *str ++ = punct; c1 = c2; } *str = '\0'; return str; } char *ssplit(char *str1, const char *str2, const char punct) { while(*str2){ *str1 ++ = *str2 ++; if(isborder(*(str2 - 1), *str2)) *str1 ++ = punct; } *str1 = '\0'; return str1; } int main(void) { char *str1 = "M02M61X0F2.5B1FG1231"; char str2[128]; puts(str1); ssplit(str2, str1, ','); if(str2[0]) puts(str2); else puts("null"); while(fsplit(str2, ',', stdin)){ if(str2[0]) puts(str2); else puts("null"); } return 0; }

  • yama5140
  • ベストアンサー率54% (136/250)
回答No.10

No.9 です。 失礼しました。 ファイルからの複数行処理の場合、i = 1; の「初期化」は、1行を読み込んだ後の2個目の while 文の前で行って下さい。 年寄りは「せっかち」でいけないね・・。

回答No.8

質問者さんに伺いたいのですが、 使用言語は C++言語 ではなく C言語 ですよね? FILE*、fgets などは C言語 の処理方法です。 C++言語 では fstream を使用します。 なお C++言語 のソースは下のほうで machongola さんが書かれています。 >isdigit, isalpha 仕組みがまだよくわからないです #define isdigit(x) ((x)>='0' && (x)<='9') こんなマクロと思っていいです (実際は他にもいろいろチェックしてると思います)。 このプログラムを組んでみましたが、isdigit だけあれば処理できます。 (英字か数字 しか出てこないので、数字でなければ英字ということになります。) >私の質問にクレームらしき回答者が クレームのつもりはありませんでした。 あくまで提案です。御気分を害したことを謝罪いたします。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.7

> 自分でもある程度考えないと > 身につかないのは重々承知しておりますので 失礼しました。私の質問にクレームらしき回答者が おられたので、誰に向けて、とは書かないで色々書 いてしまいました。質問者様を責めている訳では決 してありません。 さて、問題の方に移ります。 やはり現時点で、質問者様の仰る仕様が曖昧です。 ご自分では行うべきことがはっきりしている、と 思われているとは思いますが、それを他人に説明 してはっきりしないのは、本当に行うべきことが 分かっているのかな?という危惧は拭いきれませ ん。ここの所を具体化しない限り、全てのコード は仮説の域を出ないでしょう。 ANo.1の補足にあります次の説明 > 1D2FF4CFS56HASDAFD334F > (1),(D),(2),(FF),(4),(CFS),(56) > などのように←から順に読み込んでいって > 数字があればそこで区切るようなプログラ > ムです。 この結果何をするかを未だにはっきりしてい ません。 つまり質問者様の説明から次の2通りの表示が 考えられます。 1 D 2 FF 4 CFS 56 HASDAFD 334 F もう1つは 12456334 DFFCFSHASDAFDF それから > 1D2FF4CFS56HASDAFD334F > (1),(D),(2),(FF),(4),(CFS),(56) HA・・・以降略していますね。宜しくありません。 略すなら、最初の方を削除するなり、完全な一致を 行うように説明します。 更に > 数字があればそこで区切るようなプログラ > ムです。 数字に関しては説明がありますが、アルファ ベットに関しては説明が無い、このような 片手落ちも宜しくありません。きっちり書いて も色々な解釈が生じるのが日本語です。まして 省略して幸せになることは無い、と断言できま す。 表で説明するのが見落としを無くすのに効果が あります。 前が何か|数字|アルファベット ---------+----+--------------- はじめ |xxxx|xxxxxxxx ---------+----+--------------- 数字  |xxxx|xxxxxxxx ---------+----+--------------- アルファベット|xxxx|xxxxxxxx つまり、 1)最初に数字が来た 2)最初にアルファベットが来た 3)数字の後に数字が来た 4)数字の後にアルファベットが来た 5)アルファベットの後に数字が来た 6)アルファベットの後にアルファベットが来た という6つの条件があります。 それぞれに対して何をどうしたらいいのかが まだ曖昧だと言うことです。 更に条件をいうなら、未だに数字は1つも無い、 1つ以上の数字がある。 未だにアルファベットは1つも無い、1つ以上は ある。 という条件の組合せもあります。実はこの条件に 対して何も言及が無いので、私は仕様が曖昧とい い続けている訳です。 つまり前述の表示の仕方が2通りあり、どちらとも 分からない、ということです。 このように見ると6つの条件があるのに質問者様 は1つの説明で済ませていて、5つも省略してい ます。これは省略と言う域ではなくて、分かって いるのかな?という危惧につながる所以です。 実際にC/C++の何の関数を使うか、とか、作成す る関数の構造をどうするか、とか、所謂プログ ラム作成は、仕様をはっきりさせないと着手して も殆ど意味がありません。 なお、条件を表にしてみる癖は大切です。 2種類の条件がありますと、通常4通りの組み合わ せがありますが、常識が邪魔をして2通りしか見て 居ない人は多いです。 例えば、バカか賢いか、働き者か怠け者かといった 時に、 1)バカで怠け者 2)賢くて働き者 通常これだけです。しかし、 3)バカで働き者 4)賢くて怠け者 という組合せもあり見落としがちであり、 そこがものごとのポイントであることが 多いと思えます。 ということで、仕様をもう一度整理して 再記述されることを望みます。 その中で分からない部分があれば質問を お願い致します。 ただ、私も色々ありますので、直ぐに返事が 書けるかどうかは分かりませんが、了承を お願い致します。

zaqwe
質問者

補足

申し訳ありません。説明させていただきますね >>つまり質問者様の説明から次の2通りの表示が 考えられます 最初の質問は前者の方です つまり 1D2FF4CFS56HASDAFD334F (1),(D),(2),(FF),(4),(CFS),(56),(HASDAFD),(334),(F) のようにです。 数字があればあそこで区切るとわかりずらいこと書いてしまいました。 2つ目の質問ですが、アルファベット、数字はどちらも存在します。 もしどちらかしか存在しないとしたら切り分けの作業は必要ないので その可能性を考慮にいれてませんでした。 最初に数字がきて次に違う文字がくるまで文字列とみなします 違う文字がきたら最初からその手前までを()で括り表示。 という作業なのです。 どの関数を使うかなどに関しましては、そこをご教授いただきたいと 思っております。具体的isalphaやisdigitなどかなと漠然とした イメージはありますが仕組みがまだよくわからないです。 まだ初心者の為、浅い探りしかできないのと、プログラミングに対し 説明不備になってしまって申し訳ないです。

回答No.6

こんにちは. C言語で書いていいなら,ctype.h内のマクロを利用したらどうでしょうか. 数字であるかを判定するならisdigit, 大文字であるかを判定するならisupper, 小文字であるかを判定するならislower等のマクロが有用かと思います (これならば書き方次第で数字と文字以外が入っていても対処できます). 後は現在の状態を記録しておく変数を用意して, 状態が切り替わったら適宜改行コードを出力すれば良いと思います.

参考URL:
http://ja.wikipedia.org/wiki/%E6%A8%99%E6%BA%96C%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA
  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.5

立場の問題として、PG/SEは質問者様です。 質問者様がプログラマに問題を提出する立場な ら、私は質問が曖昧だ、などとは書きません。 丸投げをこちらが受けている訳ではありま せん。質問者様が理解し、プログラミング のために何をしたら良いかが少しでも分か って貰えることが回答者の役割と解釈して います。 質問の内容が曖昧なので、問題を論理的に 組み立てられていないように思われます。 これではプログラムは回答者様にはまだ 無理です。 ですので、プログラムの設計以前に、問題 を論理的に組み立てる勉強が必要があると 考えた訳です。 補足に、数字で区切る、というのも曖昧です。 曖昧というのは、もっと細かく区切り方、区 切ってどうする、と説明が必要です。 それが、出来ないとプログラム化が出来ない、 という意味ですね。 なお、fgetsは読み込みようの関数で、表示は fputsやprintfなどの出力系の関数を使います。

zaqwe
質問者

お礼

ご回答ありがとうございます。まだ習い始めなので勉強をたくさんしなければなりません。下記の補足欄に若干補足してあります。 ただ私としてもこれにはこの方法でいったらどうかなどのアドバイス 的なもので結構です。丸投げとはこのプログラムを書いてください などのようだと私は認識しています。自分でもある程度考えないと 身につかないのは重々承知しておりますので。

回答No.4

 こんばんは。C++とあるので、std::stringとかでは駄目なのでしょうか? #include<ostream> #include<string> #include<algorithm> #include<functional> //アルファベットであればtrueを返す static bool IsAlpha(int ch) { return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'); } //文字を分けるクラス struct separetor { separetor(const std::string& s = std::string()) : m_s(), m_b(false) { this->fire(s); } separetor(const separetor& r) : m_s(r.m_s), m_b(r.m_b) { } ~separetor(){ } separetor& operator = (const separetor& r) { if(this != &r) { this->~separetor(); new (this) separetor(r); } return *this; } //実行 bool fire(const std::string& s) { if(s.empty())return false; m_b = false; m_s.clear(); m_s += '('; std::for_each(s.begin(), s.end(), std::bind1st(std::pointer_to_binary_function<separetor*, int, bool>(_S_callback), this)); m_s += ')'; return true; } //オーバーロード friend ostream& operator << (ostream& out, const separetor& s) { return out << s.m_s; } private: static bool _S_callback(separetor* p, int ch) { return p->_M_callback(ch); } bool _M_callback(int ch) { const bool b = ::IsAlpha(ch); if(m_b != b)//フラグが違うと数字→英語又は英語→数字に切り替わった事を意味する { m_s += "),("; m_b = b; } m_s += ch; return true; } std::string m_s;//作業用の文字列クラス bool m_b;//連続を記憶するフラグ }; int main(void) { //ココでファイルから読んで来て渡す様に改良してみましょう。 cout << separetor("1D2FF4CFS56HASDAFD334F") << endl; return 0; }

回答No.3

私が読み取った仕様では ・ファイルはテキストファイルで 0~9、A~Z の文字のみ ・出力(表示)は1行に英字のみ、または数字のみ [入力例] AB57A246FGG [出力例] AB 57 A 246 FGG ↓の人へ、要求が曖昧なのはどこも一緒ですw 今を行くPG&SEは、曖昧な定義から要求を満たす設計・仕様を 提示する力が求められています。 「全部教えろ」ではなく、「こう言う解釈でいい?」と 仕様を提案するのがいいと思いますよ。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.2

仕様が把握できません。 プログラムを作る以前にプログラムで何をすべきが はっきりしていません。 言葉の内容から、かなり単純なプログラムというこ とはわかります。しかし、何をすべきかが曖昧過ぎ ます。これは問題が悪いのではなくて、問題の解釈 が上手く出来ていないと考えられます。 > あるテキストファイルを読み込んでそのファイル > の中の文字列を数字と英文字を切り分けて一行ず > つ表示する これは仕様としては確定していません。 文字と数字はバラバラなのか、文字は文字、数字は 数字で連続しているのか? 1行ずつとは表示が文字を1行、数字を1行とするのか? あるいは、入力ファイルを1行ずつ処理するのか? 数字と英字を切り分けて、何を表示するのか? まだまだ突っ込みどころはありますが、まず、理解 されていないと思われますので、問題をもう10回ぐ らい読み直して咀嚼してみて下さい。

zaqwe
質問者

補足

例えば 1D2FF4CFS56HASDAFD334Fのような文字列がずらっと並んでいるテキストファイルとして。 (1),(D),(2),(FF),(4),(CFS),(56) などのように←から順に読み込んでいって数字があればそこで区切る ようなプログラムです。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.1

> 数字と英文字を切り分けて一行ずつ表示する 入力と出力の例を挙げてください。

zaqwe
質問者

補足

例えば 1D2FF4CFS56HASDAFD334Fのような文字列がずらっと並んでいるテキストファイルとして。 (1),(D),(2),(FF),(4),(CFS),(56) などのように←から順に読み込んでいって数字があればそこで区切る ようなプログラムです。

関連するQ&A