2012年7月23日月曜日

数値から文字列への変換(int,double,float→wchar_t文字列)

#include <string>
std::to_string(num);   
この関数に数値型を入れるとstd::string型が戻る。
今となってはこれだけの事なんだがC++11以前の環境では
下に昔書いた様なめんどくさい作業が必要だったのかも知れない。
============================================
#include <windows.h>
#include <iostream>
#include <sstream> //必須なのはこれ

int main()
{
 //変換したい数値を作成
 double pai = 3.1415926535897932;

 // 変換を担うストリングストリームの作成
 //basic_stringstreamテンプレートのwchara_t版がtypedefされたもの
 std::wstringstream ss; //それがwstringstream(char版はstringstream)

 //doubleやfloatの精度指定(任意)
 //整数と少数を合わせた有効な桁数でデフォルトは6
 ss.precision(17); 

 //始めに作った数値をストリングストリームに入れる
 ss << pai;
 
 //C++の標準出力もワイド文字様のwが付いたwcoutを使う
 std::wcout << ss.str();

 //文字を加えてみる
 ss << L" = 円周率";
 ss<< std::endl; //改行

 // 少数の精度を落とす
 ss.precision(7);
 // 小数の表示を指数形式にする
              ss.setf(std::ios_base::scientific, std::ios_base::floatfield);
             // 少数をストリングストリームに追加
             ss << 3.14;

 //デバッグウインドウに出力
 OutputDebugString(ss.str().c_str()); 
 
 //文字列をクリア
 ss.str(L""); 

              ss << std::endl;
 ss << 100;
 OutputDebugString(ss.str().c_str());
getchar();
}  
             


実行結果



解説

C++的な方法でintやfloat, double等の数字の型を文字列へ変換するには標準C++ライブラリの ストリングストリーム (basic_stringstream)というテンプレートクラスが使えます。
まず始めにこのクラスのオブジェクトに変換したい数字を入れます。
そして .str() というメンバでストリング(basic_string)というテンプレートクラスのオブジェクトに変換し、
さらにそのオブジェクトからC形式の文字列のポインタを得たいならストリングのc_str()というメンバを使います。

例としては・・上のサンプルで示した通りなのですが、簡単に説明するとwchar_tの文字列を作る場合なら、

std::wstringstream ss;
という風にストリングストリームを用意し、

ss << 3 <<L"これは3です";

という風によくあるC++のストリームのメソッドで文字や数字を入れて、
wchar_tのポインタを得る時は一旦wstringオブジェクトを作り、
例)
std::wstring wst = ss.str();

そこからポインタを引き出します。
例)
const wchar_t* pws = wst.c_str();

wstringオブジェクトが消えると、このポインタが指す文字列も一緒に消えるので注意しましょう。

なお、冒頭のサンプルに示したように
ss.str().c_str()
と書けば、見た目の上ではwstringの作成部分を省略できます。

最も簡単な例
std::wstringstream ss;
ss << L"円周率="<< 3.14 <<std::endl;
OutputDebugString(ss.str().c_str());

(OutputDebugString()はWindowsのIDEのデバッグウインドウに出力する関数です。)

関数にしておくと便利でしょうか?
template <typename T> std::wstring toWstr(T tep)
{
std::wstringstream ss;
ss << tep;
return ss.str();
};

使用例1
int number = 100;

OutputDebugString(toWstr(number).c_str());

使用例2
int number = 9999;
std::wstring wstr = L"この数字は…";
wstr += toWstr(number);
OutputDebugString(wstr.c_str());


なお、やたらOutputDebugString()するための関数を
定義しまくった例がこちらにあります…。

小数点型の精度

例中の
ss.precision(); は、
浮動小数点型用の精度設定のための関数であり、整数の部分と小数点以下の部分を合計した桁数で指定します。デフォルトは6です。


名前空間

 今回のプログラムは
using namespace std;
を打っておけば
std::
をはずして名前を使う事が出来ます。


charとwchar_tの切り替え


 初心者用の文字列処理の解説の多くが
std::string
とか
std::cout <<
 を使うのですが、このままでは近年のユニコード環境の関数へ渡すワイド文字(wchar_t型)の文字列は扱えません。


マルチバイト文字列(日本ではShift-JIS)とワイド文字列(Unicode, UTF-16)の違いの基礎的な話はこのサイトが参考になります。
ユニコードにも色々あるんですがWindowsプログラミングでのユニコードの文字列は16ビットのwchar_t型の配列で表し、これをワイド文字列と言います。

C++で定義されている文字列処理に関わるクラスの多くはそのままだと、char型の文字列です。しかしこれの頭にwを付けるとwchar_t型のクラスになります。
例えば
std::string はcharの配列を管理する文字列クラスですが、これのwchar_t版は
std::wstring;
です。

 細かい話をすると
これらのクラスはテンプレートで作られています。例えば

 stringは実際はbasic_stringという名前のテンプレートクラスであり、それををcharで作る時用に、typedefでstringと命名されています。wchar_tならwstringです。

↓こんな感じ
--------------
//stringの型
typedef basic_string<char, char_traits<char>, allocator<char> >
string;

//wsrtingの型
typedef basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >
wstring;
 
-------------

同様に basic_stringstream は
---------
typedef basic_stringstream<char, char_traits<char>,
allocator<char> > stringstream;
typedef basic_stringstream<wchar_t, char_traits<wchar_t>,
 allocator<wchar_t> > wstringstream;
--------
となっています。


ストリングストリームの詳しい解説はここ
 IOStreamライブラリ自体の解説はここ
が参考になるかも知れません。

0 件のコメント: