Embarcadero Discussion Forumsの質問「AnsiString時代のTMemo SelStartがXE Unicode TMemoで使えない」の対応策を考えてみました。
C++Builder6で、固定長ファイルをTMemoに読み込み、10バイトから20バイトは氏名です、10バイトから20バイトをSelStart:10、SelLentgth:20とやって反転させていたのですが・・・
とのこと。
C++Builder 2009以降では、文字列はユニコード文字列になっているので、バイト数で範囲を選択することはできません。
選択範囲を文字数で指定する必要があります。
そこで、次のような方法を考えてみました。
- ユニコードの文字列ををシフトJISに変換します。
- シフトJISの文字列からバイト数を指定して、対象の文字列を取得します。
- 対象の文字列をユニコード文字列に変換します。
- ユニコード文字列の文字数を取得します。
- TMemoに選択範囲の文字数を設定します。
サンプルアプリケーションは次のようになっています。
Memo1のLinesプロパティには次の文字列を設定しています。
社員ID 名前 住所
各ボタンを押すと、対応する項目の範囲を選択します。
ソースコードは次の通り。
//---------------------------------------------------------------------------
/**
* 選択範囲の開始位置を取得する
* @param Start 選択範囲の開始位置のバイト数
* @return 選択開始位置の文字数
*/
int GetSelStart(UnicodeString S, int Start)
{
//シフトJISに変換する
AnsiStringT<932> ansi = S;
//シフトJISで先頭からStartバイトまでの文字を取得する
AnsiStringT<932> ansiStr = ansi.SubString(1, Start);
//ユニコードに変換する
UnicodeString uniStr = ansiStr;
//ユニコードの文字数を取得する
int length = uniStr.Length();
return length;
}
//---------------------------------------------------------------------------
/**
* 選択範囲の文字数を取得する
* @param Start 選択範囲の開始位置のバイト数
* @param Start 選択範囲の長さのバイト数
* @return 選択範囲の文字数
*/
int GetSelLength(UnicodeString S, int Start, int Length)
{
//シフトJISに変換する
AnsiStringT<932> ansi = S;
//シフトJISでStartバイト目からLengthバイト分の文字を取得する
AnsiStringT<932> ansiStr = ansi.SubString(Start + 1, Length);
//ユニコードに変換する
UnicodeString uniStr = ansiStr;
//ユニコードの文字数を取得する
int length = uniStr.Length();
return length;
}
//---------------------------------------------------------------------------
/**
* 社員IDを選択する
* 社員IDは先頭から始まり、長さは10バイト
*/
void __fastcall TForm1::ButtonIdClick(TObject *Sender)
{
Memo1->SetFocus();
//社員IDは先頭から
Memo1->SelStart = GetSelStart(Memo1->Text, 0);
//社員IDの長さは10バイトは
Memo1->SelLength = GetSelLength(Memo1->Text, 0, 10);
}
//---------------------------------------------------------------------------
/**
* 名前を選択する
* 名前は10バイト目ら始まり、長さは20バイト
*/
void __fastcall TForm1::ButtonNameClick(TObject *Sender)
{
Memo1->SetFocus();
//名前は10バイト目から
Memo1->SelStart = GetSelStart(Memo1->Text, 10);
//社員IDの長さは20バイトは
Memo1->SelLength = GetSelLength(Memo1->Text, 10, 20);
}
//---------------------------------------------------------------------------
/**
* 住所を選択する
* 住所は30バイト目ら始まり、長さは20バイト
*/
void __fastcall TForm1::ButtonAddressClick(TObject *Sender)
{
Memo1->SetFocus();
//名前は30バイト目から
Memo1->SelStart = GetSelStart(Memo1->Text, 30);
//社員IDの長さは20バイトは
Memo1->SelLength = GetSelLength(Memo1->Text, 30, 20);
}