Copyright 1999 Rogue Wave Software
Copyright 1999 Sun Microsystems, Inc.
文字列クラスの使用 |
2 |
![]() |
クラス RWCString のメンバー関数は、RWCString オブジェクトと char* の読み取り、比較、格納、復元、連結、付加、追加を行ないます。その演算子を使用すると、境界検査付き、または境界検査なしで各文字にアクセスすることができます。また、クラスは自動的にメモリー管理を行ないます。ユーザーが、文字列の文字の記憶領域を作成または削除する必要はありません。
クラス RWWString は RWCString に似ていますが、RWWString はワイド文字を処理する点が異なります。この 2 つのクラスのインタフェースは似ているため、簡単に交換することができます。これらのクラスの詳細は、『Tools.h++ 7.0 クラスライブラリ・リファレンスマニュアル』に説明してあります。この章では、RWCString の動作を示すいくつかの一般的な例をあげて、次に文字列クラスの一部の機能を説明します。
一般的な例
次の例では、文字列クラスの基本的な機能をいくつか呼び出しています。ここでは、あるマニュアル中の古いバージョン番号を新しいバージョン番号に置換するために RWCString がとる手順が示されています。
#include <rw/cstring.h> #include <rw/regexp.h> #include <rw/rstream.h> main(){ RWCString a; //1 文字列オブジェクト a を作成する RWCRegexp re("V[0-9]\\.[0-9]+"); //2 正規表現を定義する while( a.readLine(cin) ){ //3 標準入力から a に読み込む a(re) = "V4.0"; //4 一致した表現を置換する cout << a << endl; } return 0; } |
This text describes V1.2. For more information see the file install.doc. The current version V1.2 implements... |
This text describes V4.0. For more information see the file install.doc. The current version V4.0 implements... |
この操作のポイントは次の式にあります。
a(re) = "V4.0";
この例では、関数呼び出し演算子の RWCString::operator() は、正規表現の型 RWCRegexp の引数をとるように多重定義されています。演算子は、正規表現に一致する範囲を示す部分文字列か、または一致する表現が見つからない場合はヌルの部分文字列を返します。するとプログラムは、部分文字列代入演算子を呼び出して区切られた文字列を右辺の内容で置換します。ヌルの部分文字列の場合は何もしません。Tools.h++ には多重定義された演算子があるため、定義された正規表現の検索と置換を 1 つの行だけで行うことができます。
特殊文字「.」が、小数点として文字どおり読まれるようにするには、「V[0-9]\\.[0-9]+」に 2 つのバックスラッシュが必要なことがわかります。これは、コンパイラがリテラル文字列を評価するときに、バックスラッシュを 1 つ削除するためです。残ったバックスラッシュは、正規表現の評価ルーチンに対して、後に続く文字すべてを文字どおり読むように指示するものです。
次の例では、RWCString は、別の多重定義された演算子 + を使用して、文字列 s1 と s2 を連結しています。toUpper メンバー関数で文字列を小文字から大文字に変換し、その結果を cout に送ります。
RWCString s1, s2; cin >> s1 >> s2; cout << toUpper(s1+s2);
照合
ある辞書を照合する場合は、RWCString の照合演算子が便利です。これらの演算子は次のとおりです。
RWBoolean operator==(const RWCString&, const RWCString&); RWBoolean operator!=(const RWCString&, const RWCString&); RWBoolean operator< (const RWCString&, const RWCString&); RWBoolean operator<=(const RWCString&, const RWCString&); RWBoolean operator> (const RWCString&, const RWCString&); RWBoolean operator>=(const RWCString&, const RWCString&);
int RWCString::compareTo(const RWCString& str,
caseCompare = RWCString::exact) const;
この関数は、str が自己と比較して辞書的に小さいか、等しいか、大きいかによって、ゼロ未満、ゼロ、またはゼロよりも大きい整数を返します。型 caseCompare は次の値をとる enum です。
exact
大文字小文字を区別する
ignoreCase
大文字小文字を区別しない
ロケール固有の文字列照合には、次のメンバー関数を使用します。
int RWCString::collate(const RWCString& str) const;この関数は標準 C ライブラリ関数 strcoll() をカプセル化したものです。この関数は、標準 C ライブラリ関数 setlocale() のカテゴリ LC_COLLATE で設定されたロケール固有の照合規約に従って計算された結果を返します。これは比較的時間のかかる計算なので、次の大域関数を使用して文字列を事前に変換し、その結果に対してcompareTo() または論理演算子 (==、!= など) の 1 つを使用する方がよいでしょう。
RWCString strXForm(const RWCString&);RWCString については、『Tools.h++ 7.0 クラスライブラリ・リファレンスマニュアル』の項目を参照してください。関数 strxForm は、関連する大域関数に示しています。
部分文字列
独立した RWCSubString クラスは、部分文字列抽出と変更をサポートしています。公開コンストラクタはありません。RWCSubString は、RWCString の各種のメンバー関数によって間接的に作成され、機会があればすぐに破棄されます。
RWCString s("this is a string"); // 部分文字列から RWCString を作成する RWCString s2 = s(0, 4); // "this"
RWSubString は、文字列あるいは RWCString や RWCSubString への代入の中で左辺値として使用することもできます。
// RWCString を作成する RWCString article("the"); RWCString s("this is a string"); s(0, 4) = "that"; // "that is a string" s(8, 1) = article; // "that is the string"部分文字列への代入は文字列の長さを保存する演算ではありません。代入演算子の両辺の文字数が同じである必要はありません。
パターン照合
クラス RWCString は文字列検索に便利なインタフェースをサポートします。以下にその例を示します。
RWCString s("curiouser and curiouser."); size_t i = s.index("curious");このコードの断片は、s の中から "curious" の最初の出現の先頭を探します。この比較では大文字と小文字が区別されます。結果として、i が 0 に設定されます。次の出現のインデックスを見つけるには、次のように記述します。
i = s.index("curious", ++i);この結果、i が 14 に設定されます。大文字と小文字を区別しない比較の場合は、次のように記述します。
RWCString s("Curiouser and curiouser."); size_t i = s.index("curious", 0, RWCString::ignoreCase);この結果、i が 0 に設定されます。
パターンが文字列中になければ、index() は RW_NPOS という特別な値を返します。
単純な正規表現
パターン照合機能の一部として、Tools.h++ クラスライブラリは、正規表現の検索をサポートしています。正規表現の構文の詳細については、『Tools.h++ 7.0 クラスライブラリ・リファレンスマニュアル』の「RWCRegexp」を参照してください。正規表現を使用すると、部分文字列を返すことができます。たとえば、次に、すべての Windows メッセージ (接頭辞 WM_) を照合する方法を示します。
#include <rw/cstring.h> #include <rw/regexp.h> #include <rw/rstream.h> main(){ RWCString a("A message named WM_CREATE"); // 正規表現を作成して Windows メッセージを照合する RWCRegexp re("WM_[A-Z]*"); cout << a(re) << endl; return 0; } |
WM_CREATE |
拡張正規表現は、任意の長さにすることができますが、使用可能なメモリーによって制限されます。部分表現をグループ化するには丸かっこを使用し、「二者択一」正規表現を作成してパターンマッチングを行なうには記号 | を使用できます。
注 - RWCRExpr は、コンパイラが例外処理と C++ 標準ライブラリをサポートしている場合にのみ使用できます。
次の例は、拡張正規表現の機能の一部を示しています。
#include "rw/rstream.h" #include "rw/re.h" main (){ RWCRExpr re("Lisa|Betty|Eliza"); RWCString s("Betty II is the Queen of England."); s.replace(re, "Elizabeth"); cout << s << endl; s = "Leg Leg Hurrah!"; re = "Leg"; s.replace(re, "Hip", RWCString::all); cout << s << endl; } |
Elizabeth II is the Queen of England. Hip Hip Hurrah! |
文字列入出力
クラス RWCString は、iostream と Rogue Wave 仮想ストリームの両方に対する充実した入出力機能を備えています。 iostream
標準の左シフト演算子と右シフト演算子は、iostream および RWCString を処理するように多重定義されています。
ostream& operator<<(ostream& stream, const RWCString& cstr); istream& operator>>(istream& stream, RWCString& cstr); |
この意味合いは次の演算子と一致します。
ostream& operator<<(ostream& stream, const char*); istream& operator>>(istream& stream, char* p); |
これらは、コンパイラに付属の C++ 標準ライブラリで定義されています。つまり、左シフト (<<) 演算子はヌル文字で終端している文字列を所定の出力ストリームに書き込みます。右シフト (>>) 演算子は、空白で区切られているトークンを入力ストリームから RWCString に読み込み、内容を置き換えます。
その他の関数では、RWCString 入力の微妙な調整が可能です1。関数 readline() では文字列を改行 (newline) で区切ることができます。またオプションのパラメータを持ち、文字を格納する前に空白をスキップするかどうかを制御することができます。次にこの例を示します。
#include <rw/cstring.h> #include <iostream.h> #include <fstream.h> main() { RWCString line; { int count = 0; ifstream istr("testfile"); while (line.readLine(istr)) // デフォルト値を使用する: skipwhitespace (空白をスキップ) count++; cout << count << " lines, skipping whitespace.\n"; } { int count = 0; ifstream istr("testfile"); while (line.readLine(istr, FALSE)) // NB: 空白をスキップしない count++; cout << count << " lines, not skipping whitespace.\n"; } return 0; } |
line 1 line 5 |
2 lines, skipping whitespace. 5 lines, not skipping whitespace. |
Rwvistream& operator>>(RWvistream& vstream, RWCString& cstr); Rwvostream& operator<<(RWvostream& vstream, const RWCString& cstr);
トークナイザ
クラス RWCTokenizer を使用すると、適切な空白で区切られた複数のトークンに文字列を分割できます。次に例を示します。
#include <rw/ctoken.h> #include <rw/cstring.h> #include <rw/rstream.h> main(){ RWCString a("a string with five tokens"); RWCTokenizer next(a); int i = 0; // 文字列が返されるまで前進する while( !next().isNull() ) i++; cout << i << endl; return 0; } |
5 |
複数バイト文字列
クラス RWCString は、各種の文字を表わすために使用される複数バイト文字列を部分的にサポートしています (368 ページの「RWCString と RWWString による文字の地域化」を参照)。複数バイト文字は複数のバイトからなるため、バイト数による文字の長さが、文字列内の実際の文字数以上になる場合があります。
RWCString に複数バイト文字が含まれる場合は、文字数を調べるために、メンバー関数 mbLength() を使用する必要があります。これに対して、RWCString に複数バイト文字が含まれない場合、lengh() と mbLengh() の結果は同じになります。この場合は、lengh() の方が処理速度がはるかに速いため、これを使用できます。次に、複数バイト文字列 Sun を使用する例を示します。
RWCString Sun("\306\374\315\313\306\374"); cout << Sun.length(); // "6" を出力 cout << Sun.mbLength(); // "3" を出力
一般的には、複数バイト文字のうち第 2 またはそれ以降のバイトはヌル文字になることがあります。これは、文字列のバイト長が strlen() から渡される長さと必ずしも一致しないことを意味しています。内部的には RWCString は埋め込まれたヌルを受け付けないため 2、第 2 バイト以降の符号にヌル文字を使用する文字セットでも安全に使用することができます。また、RWCString::data() がヌル文字で終端する文字列を返すときは常に、その文字列の前の方にヌル文字があることも考えられますので注意してください。これらを次のプログラムにまとめます。
#include <rw/cstring.h> #include <rw/rstream.h> #include <string.h> main() { RWCString a("abc"); // 1 RWCString b("abc\0def"); // 2 RWCString c("abc\0def", 7); // 3 cout << a.length(); // "3" を出力 cout << strlen(a.data()); // "3" を出力 cout << b.length(); // "3" を出力 cout << strlen(b.data()); // "3" を出力 cout << c.length(); // "7" を出力 cout << strlen(c.data()); // "3" を出力 return 0; } |
この例では、2 つの異なるコンストラクタが使用されています。1 行目と 2 行目のコンストラクタは "const char*" の引数で、ヌル文字で終端する文字列をとります。これは引数を 1 つしかとらないので、型変換にも使用できます (ARM 12.3.1)。この結果の長さは通常の方法で決まります。すなわちヌル文字の前にあるバイト数です。3 行目のコンストラクタは "const char*" および文字列の長さをとります。コンストラクタは、これらのバイト (埋め込まれたヌルを含む) をコピーします。
RWCString のバイト長は常に RWCString::length() によって渡されます。この文字列には埋め込まれたヌルも含まれていることがあるので、この長さは strlen() から渡される結果とは一致しないことがあります。
インデックスと他の演算子 (基本的に size_t 型の引数を使用したすべての関数) はバイト単位で動作します。したがって、これらの演算子は複数バイト文字列を含む RWCString には無効です。
ワイド文字列
クラス RWWString は、各種の文字を表わすためにも使用され、ワイド文字を処理する点を除けば RWCString に似ています。ワイド文字はすべて wchar_t と同じサイズであるため、複数バイト文字よりもはるかに操作しやすいものです。
#include <rw/cstring.h> #include <rw/wstring.h> #include <assert.h> main() { RWCString Sun("\306\374\315\313\306\374"); RWWString wSun(Sun, RWWString::multiByte); // 複数バイト文字列からワ イド文字列へ RWCString check = wSun.toMultiByte(); assert(Sun==check); // OK return 0; } |
基本的には、次の特殊な RWWString コンストラクタを使用して、複数バイト文字列からワイド文字列に変換します。
RWWString(const char*, multiByte_);
RWCString 全体が ASCII 文字からなる場合は、どちらへの変更もムダはかなり削減されます。これは、変換が単一の上位ビットの操作によるものであるからです。
#include <rw/cstring.h> #include <rw/wstring.h> #include <assert.h> main() { RWCString EnglishSun("Sunday"); // Ascii 文字 assert(EnglishSun.isAscii()); // OK // Ascii からワイド文字への変換 RWWString wEnglishSun(EnglishSun, RWWString::ascii); assert(wEnglishSun.isAscii()); // OK RWCString check = wEnglishSun.toAscii(); assert(check==EnglishSun); // OK return 0; } |
メンバー関数 RWCString::isAscii() と RWWString::isAscii() が、ASCII 文字のみからなる文字列であることを確かめるため、どのように使用されているかに注意してください。ASCII からワイド文字への変換には、次のような RWWString コンストラクタが使用されていました。
RWWString(const char*, ascii_);
メンバー関数 RWWString::toAscii() はこの逆の変換に使用されています。
2
ただし、複数バイト文字列を転送するシステム関数は、このように想定する場合があります。RWCString は、このような関数を呼び出して、そのような変換を提供するだけです。