1

HTTP経由で通信するサーバーとモバイル クライアントを開発しています。サーバーは Delphi 7 で作成され(古いコードとの互換性が必要なため)、クライアントは XE6 で作成されたモバイル アプリケーションです。サーバーは、文字列を含むデータのストリームをクライアントに送信します。エンコーディングに問題があります。

サーバー上で文字列をUTF8で渡そうとします:

//Writes string to stream
procedure TStreamWrap.WriteString(Value: string);
var
  BytesCount: Longint;
  UTF8: string;
begin
  UTF8 := AnsiToUtf8(Value);
  BytesCount := Length(UTF8);

  WriteLongint(BytesCount); //It writes Longint to FStream: TStream

  if BytesCount > 0 then
    FStream.WriteBuffer(UTF8[1], BytesCount);
end;

Delphi7 で書かれているように、Value は 1 バイト文字列です。

クライアントで文字列をUTF8で読み取り、それをUnicodeにエンコードします

//Reads string from current position of stream
function TStreamWrap.ReadString: string;
var
  BytesCount: Longint;
  UTF8: String;
begin
  BytesCount := ReadLongint;
  if BytesCount = 0 then
    Result := ''
  else
  begin
    SetLength(UTF8, BytesCount);

    FStream.Read(Pointer(UTF8)^, BytesCount);

    Result := UTF8ToUnicodeString(UTF8);
  end;
end;

しかしShowMessage、文字が間違っている文字列を表示するとうまくいきません。では、Delphi 7 に文字列を保存し、モバイル アプリの XE6 に復元するにはどうすればよいでしょうか。文字列を表すデータの先頭にBOMを追加する必要がありますか?

4

2 に答える 2

4

モバイル アプリケーションで UTF8 でエンコードされた文字列を読み取るには、バイト配列とTEncodingクラスを使用します。このような:

function TStreamWrap.ReadString: string;
var
  ByteCount: Longint;
  Bytes: TBytes;
begin
  ByteCount := ReadLongint;
  if ByteCount = 0 then
  begin
    Result := '';
    exit;
  end;

  SetLength(Bytes, ByteCount);
  FStream.Read(Pointer(Bytes)^, ByteCount);
  Result := TEncoding.UTF8.GetString(Bytes);
end;

このコードは XE6 で必要なことを実行しますが、もちろん、このコードはTEncoding. さらに、TStreamWrap.WriteString実装は Delphi 7 で必要なことを行いますが、XE6 では機能しません。

Delphi 7 と Delphi XE6 の両方のバージョンで同じコード ベースを使用しているようです。つまり、これらのバージョン間で異なるテキストの処理を処理するために、条件付きコンパイルを使用する必要がある場合があります。

個人的には、の例に従ってこれを行いますTEncoding。必要なのは、ネイティブの Delphistringを UTF-8 でエンコードされたバイト配列に変換する関数と、対応する逆方向の関数です。

それでは、文字列からバイトへの関数を考えてみましょう。Delphi 7 に型があるかどうか思い出せませんTBytes。ないと思います。それでは、次のように定義しましょう。

{$IFNDEF UNICODE} // definitely use a better conditional than this in real code
type
  TBytes = array of Byte;
{$ENDIF}

次に、関数を定義できます。

function StringToUTF8Bytes(const s: string): TBytes;
{$IFDEF UNICODE}
begin
  Result := TEncoding.UTF8.GetBytes(s);
end;
{$ELSE}
var
  UTF8: UTF8String;
begin
  UTF8 := AnsiToUtf8(s);
  SetLength(Result, Length(UTF8));
  Move(Pointer(UTF8)^, Pointer(Result)^, Length(Result));
end;
{$ENDIF}

反対方向の関数は、作成するのが簡単なはずです。

カプセル化された 2 つの Delphi バージョン間のテキスト エンコーディングの処理の違いを理解したら、プログラムの残りの部分で条件付きフリー コードを記述できます。たとえば、次のようにコーディングWriteStringします。

procedure TStreamWrap.WriteString(const Value: string);
var
  UTF8: TBytes;
  ByteCount: Longint;
begin
  UTF8 := StringToUTF8Bytes(Value);
  ByteCount := Length(UTF8);
  WriteLongint(ByteCount);
  if ByteCount > 0 then
    FStream.WriteBuffer(Pointer(UTF8)^, ByteCount);
end;
于 2014-05-12T13:32:06.467 に答える
-1

それ以外の

Utf8 : String;

使用する

Utf8 : Utf8String;

クライアント上。その後、変換は自動です。

編集: クライアントはモバイル プラットフォーム上にあり、Embarcadero はモバイル コンパイラで 8 ビット文字列を排除することを決定したため、上記はこの特定のケースでは機能しません。ただし、8 ビットの UTF-8 でエンコードされた文字列がある場合は、明示的な UTF-8 変換関数を使用しなくても、Utf8String を使用して UTF-8 と Unicode 文字列をシームレスに相互に変換できます。のように使うだけ

UnicodeStringVariable := Utf8StringVariable;

また

Utf8StringVariable := UnicodeStringVariable;

コンパイラは適切な変換を挿入します。

于 2014-05-12T12:05:47.680 に答える