C++マニアック

STL の string の使い方,how to use STL string,標準テンプレートライブラリ,standard template library,文字列

このページでは STL の string の使い方について解説します。

  1. string とは
  2. string の初期化
  3. string と「MFC の CString」とのやりとり
  4. string をバイナリデータとして扱う
  5. string を連結する
  6. string は不便?
    1. Format()
    2. MakeUpper()
    3. MakeLower()
    4. TrimLeft()
    5. TrimRight()
  7. string をバリアント型にしてみる

string とは ページの先頭へ

string は、「要素が char 型の文字列」を表現するための型である、と考えている人が多いでしょう。
しかし、これは、ほんの少しだけ違います
文字列というと、普通は "abc" などのリテラルで表現される 0 で終端された、いわゆる「0 終端文字列」を思い浮かべますが、string は「0 終端文字列」ではありません。
string の中味はもっと単純な char 型の配列と考える方が実体に合っており、途中に 0 を含むことも出来ます
これは、string をバイナリデータの塊として使うこともできることを示しています。
この意味では string は vector<char> に良く似ていると言えるでしょう。

string の初期化 ページの先頭へ

string に文字列を入れるには、次のようにします。強調した部分に注目ください。

#pragma warning(disable:4786)
#include <iostream>
#include <string>
using namespace std;

int main() {
    string strText0;            // 引数なしの初期化
    string strText1 = "Hello";  // 文字列リテラルで初期化
    string strText2("Hello");   // 文字列リテラルで初期化
    cout << strText0 << endl;   // 空行になる。
    cout << strText1 << endl;   // Hello になる。
    cout << strText2 << endl;   // Hello になる。
    return 0;
}

string と「MFC の CString」とのやりとり ページの先頭へ

Windows プログラミングで VisualC++ を使っていると、いつの間にか MFC の CString を使っていて、これと string との間のコピーが必要になることもあります。
この場合、次のようにします。

    CString cstr = "AAA";   // CString オブジェクト
    string  str  = "BBB";   // string オブジェクト
    str = cstr;             // CString から string へのコピー
    cstr = str.c_str();     // string から CString へのコピー

CString から string へのコピーは、昔は str = LPCTSTR(cstr); と書かないとコピー出来ませんでしたが、最近は、単純に = で結べばできるようです。
CString に上記のように char を入れるためには、VisualC++ の設定で、「マルチバイト文字列を使用する」ようにする必要があります(念のため)。

string をバイナリデータとして扱う ページの先頭へ

冒頭でも述べたように、string はバイナリデータの塊として扱うことも出来ます。
次のように、途中に 0 を入れることも出来ます。

    string strData = "AAA";     // AAA で初期化する
    strData += char(0);         // バイト 0 を追加する。
    strData += "BBB";           // BBB を追加する。
    cout << strData << endl;    // AAA としか表示されないが、
    int iSize = strData.size(); // 実際の長さは、途中に 0 を挟んだ 7 である。

応用範囲は無限ですね。

string を連結する ページの先頭へ

二つの string オブジェクトを連結するには + 演算子を使用します。

    string strA = "AAA";
    string strB = "BBB";
    string strC = strA + strB;  // AAABBB になる。

これは vector<char> では出来ないことです。
+ 演算子は、string のデータの中に 0 が挟まれていても問題なく動作します。つまり、バイナリデータの塊を連結することもできるということですね。

元のデータを書き換えて良いのであれば、+= 演算子を使用します。

    string strA = "AAA";
    string strB = "BBB";
    strA += strB;  // strA は AAABBB になる。

string は不便? ページの先頭へ

MFC の CString にある機能で string では使えないものがあります。
例えば、次のようなものです。

  1. Format()
  2. MakeUpper()
  3. MakeLower()
  4. TrimLeft()
  5. TrimRight()

一番困るのが Format() でしょうか。これを実装してみましょう。
string から派生した STRING というクラスに実装することにします。

#pragma warning(disable:4996)
#include "stdafx.h"
#include <string>
using namespace std;
// Format() を定義してみる。
class STRING : public string {
public:
    STRING Format(const char* pcFormat, ...) {
        va_list valist; va_start(valist, pcFormat);
        const int iBufferSize = 5000;
        char acTable[iBufferSize]; {
            vsprintf_s(acTable, iBufferSize, pcFormat, valist);
            assign(acTable);    // 基本クラス string の関数
        }
        va_end(valist);
        return *this;
    }
};
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
    STRING str;
    str.Format("%d", 3);              // Format() が使えるようになった。
    printf("str = %s\n", str.c_str());  // プリントしてみる。
    return 0;
}

同様に MakeUpper() を実装してみましょう。

#pragma warning(disable:4996)
#include "stdafx.h"
#include <string>
using namespace std;
class STRING : public string {
public:
    STRING() {}
    STRING(const string& rstr) { assign(rstr); }
    STRING& MakeUpper() {
        for (int iPos = 0; iPos < size(); iPos++) {
            at(iPos) = toupper(at(iPos));
        }
        return *this;
    }
};

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
    STRING str = string("abc");
    str.MakeUpper();                  // MakeUpper() が使えるようになった。
    printf("str = %s\n", str.c_str());  // ABC になる。
    return 0;
}

TrimLeft() などは、上記と大差ないので、宿題にしておきましょう。

ナオ : って、手抜き?
店主 : ...(押し黙る店主であった。)

string をバリアント型にしてみる ページの先頭へ

文字列の "2.3" を、double 型の 2.3 に変換したいとき、次のようにしますが、

    double dValue = atof("2.3");

atof() を陽に使用しないで、変換したいという要望があります。つまり、"2.3" と 2.3 を区別しないようなバリアント型の変数を使いたいというような場合、次のようにします。

#pragma warning(disable:4996)
#include "stdafx.h"
#include <string>
using namespace std;
class STRING : public string {
public:
    ...Format() の定義略...
    operator double() { return atof(c_str()); }
    STRING operator=(double dValue) { Format("%f", dValue); return *this; }
};
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) {
    STRING strValue;
    strValue = 2.3;                 // STRING に double を代入する。
    double dValue = strValue;       // STRING を double に代入する。
    printf("strValue = %s\n", strValue.c_str());    // strValue = 2.300000
    printf("dValue   = %f\n", dValue);              // dValue   = 2.300000
    return 0;
}

int との間の変換などの定義も追加すればそれなりに動作するということですね。

ナオ : 店長、これは string で CString を越えようとしているわけですか?
店主 : ......そう見えるかね?
ナオ : 店長は CString が嫌い?
店主 : ......(なぜか、押し黙る店主であった。)