1

私はScintillaを使用し、そのエンコーディングをutf8に設定します(正しく理解していれば、これがUnicode文字と互換性を持たせる唯一の方法です)。この設定では、テキスト内の位置について話すとき、Scintillaはバイト位置を意味します。

問題は、プログラムの残りの部分でUnicodeStringを使用しており、Scintillaエディターで特定の範囲を選択する必要がある場合、UnicodeStringのcharposからUnicodeStringに対応するutf8文字列のbyteposに変換する必要があることです。 。どうすれば簡単にできますか?ありがとう。

PS、ByteToCharIndexを見つけたとき、それが必要 だと思いましたが、そのドキュメントとテストの結果によると、システムがマルチバイト文字システム(MBCS)を使用している場合にのみ機能します。

4

3 に答える 3

3

UTF8の説明を使用して、UTF8文字列を自分で解析する必要があります。キリル文字列の簡単なUTF8アナログを作成しByteToCharIndex、テストしました。

function UTF8PosToCharIndex(const S: UTF8String; Index: Integer): Integer;
var
  I: Integer;
  P: PAnsiChar;

begin
  Result:= 0;
  if (Index <= 0) or (Index > Length(S)) then Exit;
  I:= 1;
  P:= PAnsiChar(S);
  while I <= Index do begin
    if Ord(P^) and $C0 <> $80 then Inc(Result);
    Inc(I);
    Inc(P);
  end;
end;

const TestStr: UTF8String = 'abФЫВА';

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(IntToStr(UTF8PosToCharIndex(TestStr, 1))); // a = 1
  ShowMessage(IntToStr(UTF8PosToCharIndex(TestStr, 2))); // b = 2
  ShowMessage(IntToStr(UTF8PosToCharIndex(TestStr, 3))); // Ф = 3
  ShowMessage(IntToStr(UTF8PosToCharIndex(TestStr, 5))); // Ы = 4
  ShowMessage(IntToStr(UTF8PosToCharIndex(TestStr, 7))); // В = 5
end;

逆関数も問題ありません。

function CharIndexToUTF8Pos(const S: UTF8String; Index: Integer): Integer;
var
  P: PAnsiChar;

begin
  Result:= 0;
  P:= PAnsiChar(S);
  while (Result < Length(S)) and (Index > 0) do begin
    Inc(Result);
    if Ord(P^) and $C0 <> $80 then Dec(Index);
    Inc(P);
  end;
  if Index <> 0 then Result:= 0;  // char index not found
end;
于 2012-04-30T17:46:37.817 に答える
1

Sergのコードに基づいて、敬意を持って関数を作成しました。他の人にも役立つことを願って、別の回答としてここに投稿しました。代わりにSergの回答が受け入れられます。

{aUtf8StrのaCharIdx(1ベース)で指定された文字(Unicodeポイント)の最初のバイトのインデックス(1ベース)を返します。

コードは、SOメンバーのSerg( https://stackoverflow.com/users/246408/serg)によって記述されたコードに基づいてEdwinYipによって修正されます。

参照1:https ://stackoverflow.com/a/10388131/133516

参照2:http ://sergworks.wordpress.com/2012/05/01/parsing-utf8-strings/ }

function CharPosToUTF8BytePos(const aUtf8Str: UTF8String; const aCharIdx:
    Integer): Integer;
var
  p: PAnsiChar;
  charCount: Integer;
begin
  p:= PAnsiChar(aUtf8Str);
  Result:= 0;
  charCount:= 0;
  while (Result < Length(aUtf8Str)) do
  begin
    if IsUTF8LeadChar(p^) then
      Inc(charCount);

    if charCount = aCharIdx then
      Exit(Result + 1);

    Inc(p);
    Inc(Result);
  end;
end;
于 2012-05-01T05:16:11.337 に答える
0

UTF-8とUTF-16(UnicodeString使用するもの)はどちらも可変長エンコーディングです。特定のUnicodeコードポイントは、コードポイントの数値に応じて、1〜4個のシングルバイトコードユニットを使用してUTF-8でエンコードでき、1〜2個の2バイトコードユニットを使用してUTF-16でエンコードできます。UTF-16文字列内の位置を同等のUTF-8文字列内の位置に変換する唯一の方法は、位置の前にあるUTF-16コードユニットをデコードして元のUnicodeコードポイント値に戻し、UTF-に再エンコードすることです。 8コードユニット。

Scintillaと対話するコードを書き直して、UTF8String代わりに使用する方がよいようです。そうすれUnicodeStringば、そのレイヤーでUTF-8とUTF-16の間で変換する必要がなくなります。UTF8Stringコードの残りの部分と対話するときは、必要に応じてとの間で変換できUnicodeStringます。

于 2012-04-30T17:31:39.260 に答える