TStringListからvector / TStringDynArrayからvector[C++Builder]

C++Builder(およびDelphi)でよく使われるTStringListとかDynamicArrayを、std::vectorに変換したい場合がよくある。
この場合、いちいちループを回さなくても、STLライクなイテレータ操作が使える、ということを今さら公式ヘルプで知ったのでメモ。

TStringListからvector

TStringListからstd::vectorは以下のように一発で変換可能。

既存のvectorにはassignで代入。

スマートポインタでも問題ない。

文字列リストの基底クラスであるTStringsも同様。
おなじみのフォント一覧を取得するケース。

ソートされた結果を最初から得たい場合は、std::setをいきなり初期化してもいい。

 

DynamicArrayからvector

Delphi動的配列型のDynamicArrayも似たような代入が可能。

IOUtilsのTDirectory::GetFilesはディレクトリ内の全ファイルを一発で取れる便利な関数だが、この返値TStringDynArrayDynamicArray<String>のtypedefなので、同様にvector等に変換できる。

 

以上、C++Builder10.2.3 / Windows10(21H2)で確認。

[c++]文字列から1文字ずつ、サロゲートペアと異体字セレクタを考慮しつつ取り出す

Unicode文字列から「1文字ずつ」を取り出す場合、異体字セレクタやサロゲートペアを考慮に入れる必要がある。
以下、日本語環境での話(モンゴル文字の異体字セレクタ等は未対応)。

1.std::wstring(2バイト環境)の場合

以前の記事で書いたとおり、異体字セレクタは文字の末尾に4byte分の情報が付加される。(C++Builderで異体字セレクタを使う)

このため、wchar_tが2byteの場合、wstringの「1文字」が取り得るバイト数は以下の4通りになる。

「1文字」の4パターン バイト数
基本文字(基本多言語面) 2byte
サロゲートペア 4byte
基本文字の異体字セレクタ付 6byte
サロゲートペアの異体字セレクタ付 8byte

以下、文字列から、1文字ずつをstd::vectorに格納するメソッド。

(wchar_tが16bit/unsignedであることを前提にしたコード)

2.std::string(utf-8)の場合

utf-8文字列をstd::stringに突っ込んで使う場合もあるので(自分自身はやらないが)、ちょっと調べた。 以下のような方法で取り出せる(たぶん)。

utf-8文字は、先頭バイトを見ると1文字分のバイト数が分かるので、サロゲートペア判定は特に必要ない。 だが、そこで取れるバイト数には異体字セレクタ情報は反映されないので、自前で処理する必要がある。

文字に付加される異体字セレクタは計4byte分で、漢字用のIVSでは以下の範囲を取るようだ。

バイト順 値の範囲
0xF3 (固定)
0xA0 (固定)
0x84~0x87
0x80~0xBF
(0x80~0xAF)

4バイト目は、3バイト目が0x87の時に限り最大で0xAF(たぶん)。

以下、utf-8文字列の格納されたstd::stringから1文字ずつ取り出すメソッド。
なお、IVS最初の0xF3は、単体でも1byteで文字を表現するので、まず2byte分を判定する必要がある。

3.サンプルプログラム

C++Builderによるサンプルプログラム。

TFormにTEditとTMemoをひとつずつ、TButtonを2つ貼り付ける。
TEditとTMemoのフォントは游明朝、サイズを40にしておく。 TEditに以下の文字列を入れておく。

文字列の漢字部分は、最初の「辻」から順に
・基本文字
・異体字セレクタ
・基本文字
・サロゲートペア
・サロゲートペア
・サロゲートペアの異体字セレクタ付
英字は小文字のaが全角、大文字のAは半角。

3-1.std::wstringを使った例

Button1Clickを次のように実装。

結果:

3-2.std::stringを使った例

C++BuilderにはUTF8String型があるので、変換にはそれを使っている。
Button2Clickを以下のように実装。

結果:
 
以上、とりあえずのテストでは上手くいっているが、何か見落とし等があるかも。

[c++]vectorを配列に/配列をvectorに

どっちからどっちに変換するかで方法が違うため、すぐ忘れるのでメモ。

vectorから配列

std::copyを使う方法。

配列からvector

std::copyやvectorのメンバ関数assignを使う方法もあるが、c++11以降なら、以下がたぶん一番シンプル。

配列の大きさとか

以下、おまけ。
既存のvectorに配列を代入するなど、配列のサイズ(要素数)を知りたい場合、c++11以降だと、sizeofを利用する以外の方法も用意されている。

ただし、既存のvectorに、異なるサイズの配列を代入するだけなら、メモリや実行速度にシビアでなければ、いちいちサイズを求めなくとも以下で済むといえば済む。

vectorの要素をloopしながら削除(添え字版)

久しぶりにやるといつも忘れて、Web検索するハメになるけれど、イテレータの使用例ばかり出てくる(気がする)ので、添え字版をメモ。

std::dequeでも同様。