TMemoを文字列のバイト数で範囲選択するには

Embarcadero Discussion Forumsの質問「AnsiString時代のTMemo SelStartがXE Unicode TMemoで使えない」の対応策を考えてみました。

C++Builder6で、固定長ファイルをTMemoに読み込み、10バイトから20バイトは氏名です、10バイトから20バイトをSelStart:10、SelLentgth:20とやって反転させていたのですが・・・
とのこと。

C++Builder 2009以降では、文字列はユニコード文字列になっているので、バイト数で範囲を選択することはできません。
選択範囲を文字数で指定する必要があります。

そこで、次のような方法を考えてみました。

  1. ユニコードの文字列ををシフトJISに変換します。
  2. シフトJISの文字列からバイト数を指定して、対象の文字列を取得します。
  3. 対象の文字列をユニコード文字列に変換します。
  4. ユニコード文字列の文字数を取得します。
  5. TMemoに選択範囲の文字数を設定します。

サンプルアプリケーションは次のようになっています。

001

Memo1のLinesプロパティには次の文字列を設定しています。

社員ID    名前                住所                           

各ボタンを押すと、対応する項目の範囲を選択します。

002

003

004

ソースコードは次の通り。

//---------------------------------------------------------------------------
/**
 * 選択範囲の開始位置を取得する
 * @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);
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください