さとーC++ぶろぐ

アクセスカウンタ

zoom RSS C++ STLメモ5 string活用

<<   作成日時 : 2007/01/10 19:48   >>

ナイス ブログ気持玉 1 / トラックバック 0 / コメント 0

STLではないが,C++には文字列を扱うクラスstringがある。
これは,今までのC言語やC++で扱ってきた文字列 char型配列と互換性をもちつつも,圧倒的に簡単に使えるようになる。

そのうちで,私が良く使う文字列処理を紹介します。


基本:
#include <string>

using namespace std;
が必要

string str1;
str1 = "abc"; // str1に 文字列"abc"を代入(文字列自体の値のコピーである。ポインタの設定ではない) C言語の strcpy( );相当だが,メモリ確保は自動
const char *p = str1.c_str(); // C言語互換の文字列を取得する。C言語の文字列を受け取る関数に渡したりするときは,これを使う

// 文字列の代入連結の方法

string str2, str3;
str2 = "abc";
str2 += "efg"; // 文字列の連結 結果,"abcefg"となる。 C言語の strcat( );相当

str3 = "xyz";
str2 = str3; // 文字列同士の代入も,データのコピー strcpy( );

// こんな,足し算もできます。
str2 += str3 + "abc";
str2 += "abc" + str3;


// 注意:+で連結が出来ないパターン
// 出来ないパターン
char cArray[20] = "C言語文字列";
str3 = cArray + "abc"; // cArray + "abc" は,char[]とchar*型の足し算に付き,出来ません


C言語の文字列同士の足し算は,ポインタ同士のアドレスの足し算となり,意味が文字列の連結にならない。(そもそも,ポインタ同士は足し算ができない。)
この辺が,stringの限界か?,一応,代用案は以下の様になる。(左辺右辺のどちらか,一方でもstring型になっていれば,問題ない)


// 代用案
char cArray[20] = "C言語文字列";
str3 = cArray + string("abc"); // "abc"がstring型になったので,出来ます。



●文字列の基本的な操作

// 文字列の長さを取得 length()
string str4 = "abc";
int len = str4.length(); // int len = 3; と同じ

// 文字列中の特定の要素へアクセス(先頭は,0です。つぎは1,2..)
string str5 = "xyz";
char c0 = str5[0]; // char c0 = 'x'; と同じ
char c1 = str5[1]; // char c1 = 'y'; と同じ
char c2 = str5[2]; // char c2 = 'z'; と同じ

str5[1] = 'Y'; // 文字列の範囲内なら,書き換えも可能 str5 = "xYz";

// 文字列の一部をコピーして切り出す
string str3 = "abcefg";
string str4 = str3.substr( 3, 2 ); // str3の3文字目から2文字分をstr4へ代入 str4 = "ef";


●文字列検索

stringのメンバ関数 find() を使うと,文字列中に含まれる,部分文字列の位置を「検索」出来ます。まさに,検索機能です。

string str = "abc123hi123mn";
string::size_type pos; // 位置情報を保管する変数pos(実はただの整数型だったりする。int pos; と書いていけるが,あまりよくない)

pos = str.find("123"); // strの中の "123"をstrの先頭から検索する

if(pos == string::npos) // もし, pos == string::nposなら,検索で見つからなかった
{
  // 発見できず
} else {
  // 発見。
  // posは3となる。先頭から4文字目に123の1がある (先頭を0文字目とした,発見した文字列の先頭の位置が入る)
}



では,2つ目以降の "123"も探すことが出来るコードはこちら


string str = "abc123hi123mn";
string find_str = "123"; // 検索対象の文字列
string::size_type pos;

for(pos = str.find(find_str); pos != string::npos; pos = str.find(find_str, find_str.length() + pos))
{
  // 発見。
  // posは3と8となる。
}


pos = str.find(find_str, pos + find_str.length()) は, find(検索文字列, 検索開始位置) をあらわし,
検索開始位置は,pos(前回の発見位置) に find_str(検索する文字列)の文字列長を足してやる必要がある。
find_str(検索する文字列)の文字列長を足さないと,常に同じ場所を返すので,forの繰り返しが終わらなくなる。

間違った例(絶対に間違ってはいけない間違え方):
string str = "123hi123mn";
string find_str = "123";
string::size_type pos;

for(pos = str.find(find_str); pos != string::npos; pos = str.find(find_str, pos))
{
// pos は常に 0のまま。
/*
0123456789
"123hi123mn"
| pos の値 = 0 次の検索開始位置も,0なら,いきなり検索文字列を発見し,場所が0というのが戻ってくるので,posにまた0が代入される。が永久に続く。
*/

}





●文字列書き換え

string str = "abcxy123";
str.replace(3, 2. "XYZ"); // strの3文字目から,2文字を "XYZ"に置き換える。結果, str = "abcXYZ123";
// ポイント:置き換える先は,長さが変わってもよい!



// 文字列の部分削除もこれで出来る
string str = "a123abc";
str.replace(1, 3. ""); // strの 1文字目から 3文字を 空っぽの文字列"" (削除)にする str = "aabc";


// もちろん,変換後の指定にstring型も指定できます。
string str = "a123abc";
string cnv_to = "XYZ"
str.replace(1, 3. cnv_to); // strの 1文字目から 3文字を "XYZ" str = "aXYZabc";


参考:
stringクラスのreplace()の引数は他にも,stringクラスの iteratorを与えることが出来ます。
この場合,最初の2つの引数が,開始位置,終了位置の一つ先を指定します。3つ目の引数で,
書き換え後の文字列を指定します。※string型の場合は,あまりiteratorを使うことは無いでしょう。



●文字列置換(文字列検索+文字列書き換え)

文字列検索と文字列書き換えを上手く組み合わせると,置換処理が出来てしまいます。
以下に"123"を"一二三" に書き換えるプログラムの例を書きます。

これは,完全定型パターンです。


string str = "abc123hi123mn";
string find_str = "123"; // 検索対象の文字列
string rep_str = "一二三"; // 書き換え後の文字列
string::size_type pos;

for(pos = str.find(find_str); pos != string::npos; pos = str.find(find_str, rep_str.length() + pos))
{
str.replace(pos, find_str.length(), rep_str);
}


forの後ろの部分
// str.find(検索する文字列, 置換後の文字列長 + 発見・置換した位置)

replace部分
// str.replace(発見した位置であり書き換え開始位置, 検索した文字列長, 置換後の文字列);


これだけで,出来てしまうんです。全文置換が!!


もうちょっと,最適化すると以下の様な関数になります。(実用的なのはこちら)

str: 置換対象の文字列。
from : 検索文字列
to : 置換後の文字列

void ReplaceStr(string& str, const string& from, const string& to)
{
  string::size_type pos = 0;

  while(pos = str.find(from, pos), pos != string::npos) {
    str.replace(pos, from.length( ), to);
    pos += to.length();
  }
}


●basic_string とかの basic_ ってなにか? ( UNICODEやUTF-8のバージョン )

STLには,こういった basic_ で始まるテンプレートクラスがいくつかあります。これは主に,char型用とwchar_t型(UNICODE)用の両方に
対応させるテンプレートクラスのベースを作成しておき,char型は basic_を除いたもので, wchar_t型は basic_を除いて代わりに 頭に wをつけたバージョンの2が
用意されています。 そのため, マニュアルマニュアルでは,basic_ と付いていたら,読み飛ばすか,代わりに wをつけるなどして,
読み直すと,そのまま使えます。

ここではstring系のみ説明し,wstring系のUNICODE系は詳しく述べない。注意すべきは,char型が全てwchar_t型になるので,wchar_tに対応する関数やオブジェクトを使う必要があること。

※ただし,UNICODDEの表現の1つである,UTF-8は,string型で扱います。
Shift-JISから,UTF-8に変換するコードの例:
 http://www2s.biglobe.ne.jp/~satosi/soft/sjis2utf8.h
逆の関数(UTF-8からShift-JIS)も必要なのだが,まだない。




●streamとstringの関連

stream(ストリーム)系は,厳密にはSTLではないが,STLと一緒に使うことが多い。特にstringは,多い。

ストリームとstringの活用
string buf;
cin >> buf; // キーボードから文字列を入力。ただし,改行が押されてからで,頭の空白や改行やタブを除き,次の空白や改行やタブの手前までを設定
cout << buf; // 画面に出力

// C言語文字列で1行入力
char b[128];
cin.getline(b);

// string型で1行入力
string b2;
// cin.getline(b2); // なんと,これが出来ない
getline(cin, b2); // これで行う



cout や cin や,ifstream, ofstream などの,iostream系のストリーム入出力の文字列版

ストリームは,標準入出力(キーボードや画面入出力)や,ファイル入出力の以外に,文字列での入出力がある。入力元が文字列からとか,出力先が文字列にしたい場合。

たとえば,ファイルに出す前に,文字列に出力したいが,ファイルに出すのと同じような感じで出したい。ファイルから文字列に読み出してしまった後で,もう一回ファイルからと同じようにストリームで読み出したい。

などなど。無くてもよいが,便利なツール。


#include <sstream> と #include <strstream> がある。違いは以下の通り

<sstream> は stringで,ストリームを行う
istringstreamクラス(入力用)とostringstreamクラス(出力用)

<strstream> は char* (C言語互換の文字列)で,ストリームを行う
istrstreamクラス(入力用)とostrstreamクラス(出力用)


例:
string str = "10 20 30 abc";
istringstream istr(str); // 入力を stringにする。istrstream もこれと同様に使える。 他は,cinとかifstreamとかと同じ。

int a,b,c;
string s;

istr >> a >> b >> c;
istr >> s;



istringstream ostr; // 出力を stringにする。最後は,string型に戻す。ostrstream もこれと同様に使える(最後はchar*型なところが違うだけ)。他は,coutとかofstreamとかと同じ。
ostr << a << endl;
ostr << b << endl;
ostr << c << endl;
ostr << s << endl;

str = ostr.str(); // string型に戻す

テーマ

関連テーマ 一覧


月別リンク

ブログ気持玉

クリックして気持ちを伝えよう!
ログインしてクリックすれば、自分のブログへのリンクが付きます。
→ログインへ
気持玉数 : 1
ナイス

トラックバック(0件)

タイトル (本文) ブログ名/日時

トラックバック用URL help


自分のブログにトラックバック記事作成(会員用) help

タイトル
本 文

コメント(0件)

内 容 ニックネーム/日時

コメントする help

ニックネーム
URL(任意)
本 文
C++ STLメモ5 string活用 さとーC++ぶろぐ/BIGLOBEウェブリブログ
文字サイズ:       閉じる