もっとスマートなコーディングありませんか?

[戻る]
wood 2003/02/28(金) 06:55:36
Win XP VC++6 MFC

カンマ付き文字列からdouble型の値を取り出す
目的のものです
少数点以下のレングスは不定(double型で扱える範囲内)
整数部は符号を含め18桁以内

例)
 (引数)KString →  戻り値

”-123,456.89”   → -123456.89
”\-123,456.89”  → -123456.89
”\-123,456.89001” → -123456.89001
”abc-123,456.81”  → -123456.81

こんなコード書きました(hogehoge.DLL)

double    hogehoge::COR_KStoDouble(CString *KString)
{
int    PT_SZ;
int    PT_INDT_IDX;
int    PT_OTDT_IDX;
double    m_Anser;
char    *m_Str    = new char[KString->GetLength() + 1];
PT_SZ        = KString->GetLength();
for(PT_OTDT_IDX = 0;PT_OTDT_IDX <    PT_SZ;PT_OTDT_IDX++){
*(m_Str + PT_OTDT_IDX)=' ';
}

*(m_Str + PT_OTDT_IDX)='\0';

PT_OTDT_IDX    = PT_SZ -1;

for(PT_INDT_IDX    = PT_SZ - 1;PT_INDT_IDX > -1;PT_INDT_IDX--){

----------特に ここから ---------------
if(KString->GetAt(PT_INDT_IDX) =='-'||
 KString->GetAt(PT_INDT_IDX)=='.'||
 KString->GetAt(PT_INDT_IDX)=='0'||
 KString->GetAt(PT_INDT_IDX)=='1'||
 KString->GetAt(PT_INDT_IDX)=='2'||
 KString->GetAt(PT_INDT_IDX)=='3'||
 KString->GetAt(PT_INDT_IDX)=='4'||
 KString->GetAt(PT_INDT_IDX)=='5'||
 KString->GetAt(PT_INDT_IDX)=='6'||
 KString->GetAt(PT_INDT_IDX)=='7'||
 KString->GetAt(PT_INDT_IDX)=='8'||
 KString->GetAt(PT_INDT_IDX)=='9'    )    {
----------ここまでの判断方法を何とかしたい---------

 *(m_Str + PT_OTDT_IDX)    = KString->GetAt(PT_INDT_IDX);
 PT_OTDT_IDX--;
 }
}
m_Anser    = atof((const char *)m_Str);
delete m_Str;
return m_Anser;
}

STLの学習はしていませんが使って簡単になるなら教えてください
多少変なコーディングあるけど、独学なのでご容赦ください
なお、使い方の間違いもご指摘いただけるとありがたいです

コンパイルはとおり、実行も可能なコードです
例に載せた内容の結果は取得できています

よろしくお願いします

επιστημη 2003/02/28(金) 07:17:16
VC++7 で動作確認しました。

#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
#include <functional>

// 余分な文字 すなわち"-.0123456789"以外の文字に対し true を返す
struct not_numeric : std::unary_function<char,bool> {
  bool operator()(char x) const {
    static std::string numeric = "-.0123456789";
    return numeric.find(x) == std::string::npos;
  }
};

int main() {
  std::string input = "\\-123,456.789";
  std::string result;

  // inputから余分な文字を抜いたresultを作る
  std::remove_copy_if(input.begin(), input.end(), 
                      std::back_inserter(result), not_numeric());

  std::cout << '[' << result << ']' << std::endl;
  return 0;
}

wood 2003/02/28(金) 07:54:03
επιστημη さん 早々のご回答ありがとうございます
C++の基礎が出来ていない私ですが
ご掲示いただいたコードを参考に学習させていただきます

ここで「済み」つけたいところですが
自分なりにどう取り込めるか試してみてからにします

>  std::remove_copy_if(input.begin(), input.end(), 
>                      std::back_inserter(result), not_numeric());
これで何でresultがdouble型で四則演算可能な値として取得出来るのか、
私自身わかっていないのも理由のひとつです

今晩帰ってきてから、早速試してみたいと思います
ありがとうございました

ごめんなさい「四則演算可能な値」なんていってませんでしたね

Kazuki 2003/02/28(金) 09:14:33
istringstreamを使えば文字列からの変換は簡単です

#include <iostream> //cout cin
#include <string>   //string
#include <sstream>  //istringstream

int main()
{
  std::string str = "-3.14";
  std::istringstream iss(str);
  double value;
  iss >> value;
  std::cout << value << std::endl;
  
  return 0;
}

επιστημη 2003/02/28(金) 09:29:49
> istringstreamを使えば文字列からの変換は簡単です
なるほど。じゃ併せ技で。

#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <algorithm>
#include <iterator>
#include <functional>

// 余分な文字 すなわち"-.0123456789"以外の文字に対し true を返す
struct not_numeric : std::unary_function<char,bool> {
  bool operator()(char x) const {
    static std::string numeric = "-.0123456789";
    return numeric.find(x) == std::string::npos;
  }
};

int main() {
  std::string input = "\\-123,456.789";

  // 余分な文字を取り除き、ストリームに流し込む
  std::stringstream strm(input);
  std::remove_copy_if(input.begin(), input.end(), 
                      std::ostream_iterator<char>(strm),
                      not_numeric());

  // ストリームからdoubleで吸い出す
  double result;
  strm >> result;

  std::cout << '[' << std::setprecision(9) << result << ']' << std::endl;
  return 0;
}

επιστημη 2003/02/28(金) 09:32:29
いたたた、一箇所ちょんぼ。

  // 余分な文字を取り除き、ストリームに流し込む
×:  std::stringstream strm(input);
○:  std::stringstream strm;

失礼ぶっこきました。

επιστημη 2003/02/28(金) 10:30:33
おっと、読み流してた...

>>  std::remove_copy_if(input.begin(), input.end(), 
>>                      std::back_inserter(result), not_numeric());
> これで何でresultがdouble型で四則演算可能な値として取得出来るのか、
> 私自身わかっていないのも理由のひとつです

できません(やってません)よ。余分な文字を抜いた文字列を作っただけです。
文字列から数値への変換はどうにでもすればいい。

wood 2003/03/01(土) 09:52:59
[[解決]]
出来ました「Kazuki さん επιστημη さん」ありがとうございました

結果

--------------------SSMCORE.h------------------
#include "imm.h"
#include <iostream>
#include <functional>
#include <algorithm>
#include <sstream>
class AFX_EXT_CLASS SSMCORE 
{
public:
 SSMCORE();
 ~SSMCORE();
   ・
   ・
   ・
//  カンマ、少数付き文字列をdoubleに変換
 double    COR_KStoDouble(CString *);
private:
   ・
   ・
   ・
 struct not_numeric : std::unary_function<char,bool> {
    bool operator()(char x) const {
        static std::string numeric = "-.0123456789";
        return numeric.find(x) == std::string::npos;
    }
 };
};

--------------------SSMCORE.cpp------------------

double    SSMCORE::COR_KStoDouble(CString *KString)
{
  double result;

  std::string input = *KString;
  std::stringstream strm;
  std::remove_copy_if(input.begin(), input.end(), 
                      std::ostream_iterator<char>(strm),
              SSMCORE::not_numeric());

  // ストリームからdoubleで吸い出す
  strm >> result;
 
  return result;

}
--------------------------------------------------
まだ単純に取り込んだだけで、
>struct not_numeric : std::unary_function<char,bool> 
がなんでこう言う定義になっているかわかっていないので
勉強します
>"-.0123456789
これだけはわかりますけど

次のステップ
doubleがたを"\-123,123.01"にすることなので
自力で(本屋さんへ行って STLの本かって)勉強して
やってみたいと思います、本当にありがとうございました

COBOLプログラマーがC++やるの大変です
最初に掲示したのだってコーディング・コンパイル・デバック
に5時間くらいかかって作ってますから

頭の中は 2×3は2+2+2でそのまま
for(i=1;i<3;i++){a=a+2]
のような頭ですから...

επιστημη 2003/03/02(日) 03:19:42
std::stringを持ち出すまでもなかったかな。
remove_copy_if / remove_if は char[] に対しても
使えるんだし。

επιστημη 2003/03/03(月) 13:59:07
> std::stringを持ち出すまでもなかったかな。

#include <afx.h>
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cstdlib>

using namespace std;

struct not_numeric {
  bool operator()(char x) const {
    static const char numeric[] = "-.0123456789";
    return std::find(numeric, numeric+12, x) == numeric+12;
  }
};

double str2double(CString* KString) {
  const char* source = static_cast<const char*>(*KString);
  char buffer[128]; // 大きさテキトー
  *std::remove_copy_if(source, source+strlen(source),
                       buffer, not_numeric()) = '\0';
  return atof(buffer);
}

int main() {
  CString str = "-\\123,456.789";
  std::cout << std::setprecision(12) << str2double(&str);
  return 0;
}

古いスレッドには追加発言できません。