STLでの文字列作成について

[戻る]
sunyopu 2004/11/05(金) 23:20:02
現在携わっている仕事(環境:WinXP,VC++6.0)で、
あるプログラムを作成しているのですが、
移植性を高めるためにMFCを使用しないという
ルールになっています。

普段、文字列操作には 
MFC の CString を使用しているのですが、
今回は STL の string を使っています。

大半は不自由ないのですが、
数値を文字列にする場合、以下のような手法しか
分からず多少面倒です。

  char caWork[100];
  sprintf(caWork, "%d %s … ", 11111, "aaaa", …);
  string strWork = caWork;

CString の場合は、CString::Format() で
バッファサイズを意識することもなく簡潔に記述できるのですが、
string でも似たようなことができないものでしょうか?

もう少しすっきりコーディングしたいな思っています。
何かいい手法があったらお教え願いたいです。

Ban 2004/11/06(土) 00:08:34
#include <sstream>
#include <string>

.....

std::ostringstream oss;
oss << 11111 << " " << "aaaa";
std::string strWork = oss.str();

こんな感じ?

Ban 2004/11/06(土) 00:27:04
> 数値を文字列にする場合、

環境がゆるすなら boost を導入するとか、

    std::string strWork = boost::lexical_cast<std::string>(11111);

このイメージで stringstream のラッパを自作するのもアリでしょうか。

επιστημη 2004/11/06(土) 01:07:12
lexical_cast の実装それ自体、 stringstream のラッパです ^^;

Ban 2004/11/06(土) 01:18:45
>επιστημηさん

> lexical_cast の実装それ自体、 stringstream のラッパです ^^;

御意。ヘッダ内も読んでますからこの事自体は知ってますが、
ただ「実績のない外のライブラリは使っちゃいかんっ」って
現場もあったりするので、わざわざ車輪の再発明が必要かもと
思いまして>自作
# 実は経験者(^ ^;

επιστημη 2004/11/06(土) 01:25:31
あるいはsprintfをラップして:

std::string form(const char* format, ...)

をこしらえますか。

sunyopu 2004/11/06(土) 22:28:58
[[解決]]
みなさん、
ご返事ありがとうございます。

> std::ostringstream oss;
> oss << 11111 << " " << "aaaa";
> std::string strWork = oss.str();

勉強になります。
これなら簡潔になりますね。

欲をいえば、
sprintfとかの書式指定(%05dとか%3.2f)が
使えればいいのですが...

> 環境がゆるすなら boost を導入するとか、

自分自身、boostの概要くらいしか知らず、
仕事での納期もあるため次の機会にしたいです。
個人的には大いに興味があります。

> あるいはsprintfをラップして:

そういう方法もありますね。
バッファサイズを意識しないで使えるように
実装できれば完璧だと思います。
(難しそうではありますが...)

日ごろはCStringを何気なく使っていますが、
使えないと便利さが再認識させられます。

状況に応じて色々やってみようと思います。

monkey 2004/11/06(土) 23:36:58
> 欲をいえば、
> sprintfとかの書式指定(%05dとか%3.2f)が
> 使えればいいのですが...

書式指定にはマニピュレータと言われるものを使います。

// sample
#include <sstream>
#include <iomanip>
#include <string>
#include <iostream>

int main()
{
    using namespace std;

    int    n = 123;
    double r = 1.2;

    ostringstream oss;
    oss << setw( 5 ) << setfill( '0' ) << n << " "
        << setw( 3 ) << fixed << setprecision( 2 ) << r;

    string s = oss.str();

    cout << s << endl;
}

Ban 2004/11/07(日) 00:05:37
> バッファサイズを意識しないで使えるように
> 実装できれば完璧だと思います。

とりあえずVC.NET2003だとこんな感じでしょうか。

std::string
form(const char* const format, ...)
{
  va_list           arguments;
  std::vector<char> buffer;

  assert(format);
  va_start(arguments, format);
  try{
    int length = _vscprintf(format, arguments) + 1;
    if(length < 1)   throw std::runtime_error(format);
    buffer.resize(length);
    int result = vsprintf(&buffer.front(), format, arguments);
    if(result < 0)   throw std::runtime_error(format);
    buffer[length-1]    = '\0';    // 保険
  }
  catch(...)
  {
    va_end(arguments);
    throw;
  }
  va_end(arguments);
  return &buffer.front();
}

残念ながら VC6 だとバッファ長を取得する _vscprintf が
使えないのでちょっと面倒かも。vector::front も使えなかった....。

# なお、上の例だと vector が連続領域に確保されるSTLの実装系に
# 依存しますので、boost::scoped_array あたりにした方がいいかも。

Ban 2004/11/07(日) 00:23:15
boost は読んでてい"ため"になりますし、けっこう面白いです。
# いや、便利なものも多数ありますよ、ちゃんと(^ ^;

> sprintfとかの書式指定(%05dとか%3.2f)が
boost::basic_format なら、
C++ のマニピュレータ指定を C の printf 風に記述できたりします。
# %演算子のオーヴァロードで実装されてます。

実際に使うのかと言われたらまずいらないと思いますが....
オーヴァロードのハックの例でしょうか。(^ ^;

sunyopu 2004/11/08(月) 02:09:08
Ban さん、
色々お教えいただきありがとうございます。
大変勉強になります。

> 書式指定にはマニピュレータと言われるものを使います。

これを使用すれば書式指定ができるのですね。
ぜひ使用したいと思います。

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