2012-04-30 35 views
1

私はScintillaを使用し、utf8にエンコーディングを設定します(これがUnicode文字と正しく互換性があるようにする唯一の方法です)。この設定で、の位置についてテキストScintillaの意味でバイトポジションを意味します。utf8文字列のUnicodeStringのchar posをバイト位置に変換する

問題は、プログラムの残りの部分でUnicodeStringを使用し、Scintillaエディタで特定の鳴動音を選択する必要があるとき、UnicodeStringのchar posからバイトposにutf8文字列で変換する必要があるUnicodeStringに対応します。どのようにすれば簡単にできますか?ありがとう。

PS私が見つけたとき、私はそれが私の必要なものだと思ったが、その文書とテストの結果によると、システムがマルチバイト文字システム(MBCS)を使用している場合にのみ動作する。

+0

あなたはdoesnのByteToCharIndexてください。仕事は?ドキュメントのテキストがAnsiStringが独自のコードページを運ぶように変更されたDelphi 2009より前のものであれば、私は驚くことはありません。 AnsiStringにコードページが含まれているので、システム設定に依存する代わりに、文字列がMBCS、SBCS、またはUTF-8としてエンコードされているかどうかを知ることができるはずです。 –

+0

@RobKennedy - 動作しません。それ以上の場合、Windows関数 'CharNextExA'もUTF8では動作しません。 – kludg

+0

はい、Sergが確認したように動作しません。私も試しました。 –

答えて

3

UTF8 descriptionを使用してUTF8文字列を自分で解析する必要があります。私はByteToCharIndexの迅速なUTF8アナログを書かれており、キリル文字列にテストした:

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; 
+0

ありがとうSerg!あなたのUTF8PosToCharIndex関数も間違いなく便利ですが、実際には、私はこのSOの質問で何を求めているのは逆の関数CharIndexToUTF8Posです。あなたのfuncは私にとって素晴らしい例です(私はutf-8の仕様を勉強して、私が実装できるかどうか、あるいはあなたに私にいくつかのヒントを教えてください:) –

+0

@EdwinYip - 私は短いブログを書いていますあなたの質問に関連する投稿 - http://sergworks.wordpress.com/2012/05/01/parsing-utf8-strings/ – kludg

+0

あなたの助けてくれてありがとう、私はあなたのコードから派生した関数で私の問題を解決し、私は以下の別の答え。 –

0

UTF-8とUTF-16(どれがUnicodeStringであるか)は可変長エンコードです。指定されたUnicodeコードポイントは、コードポイントの数値に応じて、1〜4バイトのコードユニットを使用してUTF-8で、1〜2バイトのコードユニットを使用してUTF-16でコード化することができます。 UTF-16文字列内の位置をUTF-8文字列内の位置に変換する唯一の方法は、UTF-16コード単位を元のUnicodeコードポイント値に戻す前にデコードし、次にUTF- 8コードユニット。

UnicodeStringの代わりにUTF8Stringの代わりにScintillaとやりとりするコードを書き直したほうが良いと思われる場合、そのレイヤーでUTF-8とUTF-16の間で変換する必要はありません。残りのコードとやり取りする場合は、必要に応じてUTF8StringUnicodeStringの間で変換できます。

+0

サードパーティのlib。私はUnicodeStringを扱います...そしてUnicodeString(別名D2009以上の文字列)を使うことの利便性は、内部エンコーディングについて気にする必要はなく、文字列を "文字の配列"として扱うことができます。コンパイラは、1文字が2バイト以上かどうかに注意します。 –

1

私は素晴らしいとSergのコードに基づいて機能を書きました私は他の人にも役立つことを望む別の答えとしてここに掲示しました。代わりにSergの答えが受け入れられます。

{aUtf8StrでaCharIdx(1ベース)によって指定された文字(ユニコードポイント) の最初のバイトのインデックス(1ベース)を返します。 REF 2 https://stackoverflow.com/a/10388131/133516

コードが1 SOメンバーSerg(https://stackoverflow.com/users/246408/serg

REFによって書かれたコードに基づいて、エドウィン・イップによって改正され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; 
関連する問題