.NET Framework対応のアプリケーションが扱う文字列に4バイト長で1文字を表す「サロゲート・ペア」が含まれる場合,文字列操作にどのような影響があるだろうか。文字列処理で最も基本的で頻繁に利用されるstringクラス(stringオブジェクト)に着目した検証記事の後編である。今回は,サロゲート・ペアが含まれていても正常に動作する例などを紹介しよう。
前編で検証したように,stringオブジェクトに関する,文字数や文字単位のアクセスに関するメソッドや,インデックス値を求めるメソッドは,扱う文字列にサロゲート・ペアが含まれると,文字の見た目(人間が認識している文字の形や数)から予想されるのとは異なる結果が得られることがわかった。
しかしだからといって,文字列を操作するメソッドがすべて,サロゲート・ペアによって「正しく動作しなくなる」というわけではない。そうではない例を,いくつか示そう。
文字列の比較と加工など
まずは,文字列の比較や加工に関するメソッドを検証する(表3)。これらのメソッドの中には,理論的に考えて,サロゲート・ペアを使用する影響がないと言えるメソッドがある。
例えば,単に二つのstringオブジェクトを連結する操作なら,文字数の情報は特別重要ではない。表で「×印」が付いているプロパティは,サロゲート・ペアが存在すると,「正しく動作しなくなる」メソッド(見た目の文字数単位での処理にはならないメソッド)であるが,×が付かないメソッドは,サロゲート・ペアの影響を受けない。
表3●文字列の比較や加工に関するメソッド
|
×がつくのは,引数で文字列の一部を指定する際に,インデックスを指定するメソッドである。これらのインデックスは,charオブジェクト単位である。もし,「文字数」という単位でインデックスを指定する必要があるのなら,そのまま引数に指定して,利用してはならない。
しかし,文字列の操作全般にわたり,インデックスがchar単位であるという一貫性が保たれているので,かえって好都合な場合もある。リスト7のInsertMyData1メソッドとInsertMyData2メソッドでは,簡単な文字列の加工を行うもので,どちらも,特定の文字を検出して,その直前に文字列を追加している。前者のメソッドでは,IndexOfメソッドとSubstringメソッド,後者のメソッドではIndexOfとInsertメソッドを使用している。
リスト7:char単位のインデックスを指定して文字列の加工
|
この例では,TestProc04メソッドから,前述の二つのメソッドを呼び出して,文字列の「です」の直前に,「など」や「等」を追加している。
この二つのメソッドでは,一貫してchar単位のインデックスを使っているので,問題なく動作する。(1)では,特定の文字を検索しているが,その位置(変数ndx)は,char単位であって,本当の文字の位置ではない。文字列にサロゲート・ペアが含まれると,実際の可読できる文字の位置と一致しなくなる。しかし,(2)で文字を抽出するときも,その引数は,文字単位ではなくchar単位であるため,問題なく正しい位置の文字を抽出できる。
(2)では,Substringメソッドの2番目の引数によって,先頭からndx個分のcharオブジェクトを抽出するので,検索位置より前の文字列がうまく抽出できる。同様に(3)でも,char単位の正しい位置に文字列を挿入できる。
実行した結果は,図7のようになる。「サケ」と「ホッケ」の二つの文字列の「です」の位置は,文字数としては同じだが,InserMydata1メソッドを呼び出す際のインデックスは,4や5と異なります(インデックスは0から始まるので,charオブジェクト数でいうと,それぞれ,5個目と6個目です)。しかし,「です」の前に「など」を正しく追加できています。
図7●リスト7の実行結果。文字を正しく追加できている |
ただし,このようなロジックを実装する際,落とし穴があることに気をつけていただきたい。それは,文字列内において「一つ前の文字」や「一つ後の文字」を参照するとき,インデックス値を1減算したり,1加算したりしてはならないということだ。charオブジェクト単位のインデックスが,サロゲート・ペアの中途半端な位置を示してしまう可能性があるからだ。