Преобразование строки AnsiString в строку Unicode - PullRequest
5 голосов
/ 01 апреля 2010

Я конвертирую программу D2006 в D2010. У меня есть значение, хранящееся в одном байте на символьную строку в моей базе данных, и мне нужно загрузить его в элемент управления с LoadFromStream, поэтому я планировал записать строку в поток и использовать ее с LoadFromStream. Но это не сработало. При изучении проблемы я вижу проблему, которая говорит мне, что я не совсем понимаю, как работает преобразование из строки AnsiString в строку Unicode. Вот фрагмент автономного кода, который иллюстрирует проблему, с которой я смущен:;

procedure TForm1.Button1Click(Sender: TObject); {$O-}
var
  sBuffer: String;
  oStringStream: TStringStream;
  sAnsiString: AnsiString;
  sUnicodeString: String;
  iSize1,
  iSize2: Word;
begin
  sAnsiString := '12345';
  oStringStream := TStringStream.Create(sBuffer);
  sUnicodeString := sAnsiString;
  iSize1 := StringElementSize(sAnsiString);
  iSize2 := StringElementSize(sUnicodeString);
  oStringStream.WriteString(sUnicodeString);
end;

Если разбить последнюю строку и проверить свойство Bytes в oStringStream, вы увидите, что оно выглядит так:

Bytes (49 {$31}, 50 {$32}, 51 {$33}, 52 {$34}, 53 {$35}

Я ожидал, что это может выглядеть примерно так:

(49 {$31}, 00 {$00}, 50 {$32}, 00 {$00}, 51 {$33}, 00 {$00}, 
 52 {$34}, 00 {$00}, 53 {$35}, 00 {$00} ...

Видимо, мои ожидания ошибочны. Но как конвертировать AnsiString в юникод?

Я не получаю правильных результатов из LoadFromStream, потому что он читает из потока два байта за раз, но данные, которые он получает, расположены не так. Что я должен сделать, чтобы дать LoadFromStream правильно сформированный поток данных, основанный на строке Unicode?

Спасибо за вашу помощь.

Ответы [ 4 ]

5 голосов
/ 01 апреля 2010

Какой тип параметра oStringStream.WriteString? Если это AnsiString, у вас есть неявное преобразование из Unicode в Ansi, и это объясняет ваш пример.


Обновлено: теперь реальный вопрос заключается в том, как TStringStream хранит данные внутри. В следующем примере кода (Delphi 2009)

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  SS: TStringStream;

begin
  S:= 'asdfg';
  SS:= TStringStream.Create(S);  // 1 byte per char
  SS.WriteString('321');
  Label1.Caption:= SS.DataString;
  SS.Free;
end;

TStringStream внутренне использует системную кодировку ANSI по умолчанию (1 байт на символ). Процедуры конструктора и WriteString преобразуют строковый аргумент из Unicode в ANSI.

Чтобы переопределить это поведение, вы должны явно объявить кодировку в конструкторе:

procedure TForm1.Button1Click(Sender: TObject);
var
  S: string;
  SS: TStringStream;

begin
  S:= 'asdfg';
  SS:= TStringStream.Create(S, TEncoding.Unicode);  // 2 bytes per char
  SS.WriteString('321');
  Label1.Caption:= SS.DataString;
  SS.Free;
end;
1 голос
/ 07 августа 2018

В последних версиях Delphi вы могли использовать TEncoding:

TEncoding.UTF8.GetString(TEncoding.ANSI.GetBytes(MyString))
0 голосов
/ 01 апреля 2010

Формат потока во многом зависит от TStringStream.Encoding. В вашем примере используемая кодовая страница должна быть такой же, как sBuffer (см. Имплантацию из TStringStream.Create).

Поскольку oStringStream.WriteString(sUnicodeStream);, похоже, сохраняется как один байт, я бы предположил, что sBuffer является Ansistring или RawByteString.

Теперь ... почему чтение не удается ... Вы еще не предоставили нам пример того, как вы читаете обратно в этом потоке.

0 голосов
/ 01 апреля 2010

Я думаю, что вы хотите использовать:

LoadFromStream(stream, TEncoding.ASCII);

Если ваш однобайтовый текст не является ASCII, но основан на кодовой странице, то это может сработать:

LoadFromStream(stream, TEncoding.GetEncoding(1252));

где "1252" - это кодовая страница, на которой основан ваш однобайтовый текст.

...