WideStringを直接TStringsで持つ
ウムラウトのようなUnicode文字をTStringListに直接持ってしまおうというちょっと外道チックな方法。
始めに
UnicodeとAnsiStringの可逆変換でTStringsは直接WideStringを持つことができないと書きましたが、TStringListならば変則的ではあるものの直接WideStringを持たせることができます。
AddObjectを利用する方法とは違い、WideStringの並びのままのバイト列をコピーしたAnsiStringをセットし、取り出す時はabsolute指令を使います。
AddObjectを利用した場合と比べてオブジェクトを開放する必要がないメリットがあります。
とはいえこのままでOKというわけにはいかず、UTF-8を直接TStringListに持つ場合同様TStringListには持てるけれどもTListBoxやTComboBoxなどではこの方法で持たせることはできません。
それでは使えないじゃないか…とも思ったのですが仮想リストボックスで対処できそうなので、ちょっと面倒ですが読み込みが速くなるなどのメリットもあるので将来のコンポーネント化も視野に入れて実験してみます。
{TMyUStringList}
type
TMyUStringList = class(TMyWStrings)
protected
function WideToAnsi(sStr: WideString): AnsiString; override;
function AnsiToWide(sStr: AnsiString): WideString; override;
end;
//------------------------------------------------------------------------------
{TMyUStringList}
function TMyUStringList.WideToAnsi(sStr: WideString): AnsiString;
//WideStringの並びのままのバイト列をAnsiStringとしてコピーして返す
var
li_Len: Integer;
begin
li_Len := Length(sStr) +1;
SetLength(Result, li_Len * 2);
lstrcpynW(PWideChar(PAnsiChar(Result)), PWideChar(sStr), li_Len);
end;
function TMyUStringList.AnsiToWide(sStr: AnsiString): WideString;
//↑を元に戻す
var
lp_Src: PAnsiChar;
lp_Wide: PWideChar absolute lp_Src;
begin
lp_Src := PAnsiChar(sStr);
Result := WideString(lp_Wide);
end;
TMyWStringsを継承したクラスにしているのでTStringsと同じような使い方ができます。
li_Len := Length(sWStr) +1;
SetLength(Result, li_Len * 2);
lstrcpynw(PWideChar(PAnsiChar(Result)), PWideChar(sWStr), li_Len);
SetLengthで領域を確保してlstrcpynWでワイド文字列をコピーしますが、そのときAnsiString型のResultをPAnsiCharとPWideCharで二回キャストするところがミソ。
var
lp_Str: PAnsiChar;
lp_Wide: PWideChar absolute lp_Src;
begin
lp_Str := PAnsiChar(sStr);
Result := WideString(lp_Wide);
取り出すときはabsolute指令を使います。
WideString(PWideChar(PAnsiChar(sStr)))はいけることもあるのですがだめな場合もあるので使えません。
ListBoxで使うときはTListBoxのStyleプロパティをlbVirtualやlbVirtualOwnerDrawにした仮想リストボックスにしないと使えません。
2008-06-13: