Хранение UTF-8 представляет в виде строки в UnicodeString

В Delphi 2007 можно сохранить строку UTF-8 в WideString и затем передать это на функцию Win32, например.

var
  UnicodeStr: WideString;
  UTF8Str: WideString;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;

Delphi 2007 не вмешивается в содержание UTF8Str, т.е. это оставляют как UTF-8 закодированная строка, сохраненная в WideString.

Но в Delphi 2010 я изо всех сил пытаюсь найти способ сделать то же самое, т.е. сохранить UTF-8 закодированная строка в WideString без него автоматически преобразовываемый из UTF-8. Я не могу передать указатель на строку UTF-8 (или RawByteString), например, следующее не будет, очевидно, работать:

var
  UnicodeStr: WideString;
  UTF8Str: UTF8String;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;
9
задан Peter Mortensen 27 January 2016 в 16:14
поделиться

3 ответа

Ваш исходный код Delphi 2007 преобразовывал строку UTF-8 в широкую строку с использованием кодовой страницы ANSI. Чтобы сделать то же самое в Delphi 2010, вы должны использовать SetCodePage с параметром Convert false.

var
  UnicodeStr: UnicodeString;
  UTF8Str: RawByteString;
begin
  UTF8Str := UTF8Encode('some unicode text');
  SetCodePage(UTF8Str, 0, False);
  UnicodeStr := UTF8Str;
  Windows.SomeFunction(PWideChar(UnicodeStr), ...)
13
ответ дан 4 December 2019 в 13:00
поделиться

Хм, зачем ты это делаешь? Почему вы кодируете WideString в UTF-8, чтобы снова сохранить его обратно в WideString? Очевидно, вы используете Unicode-версию Windows API. Таким образом, нет необходимости использовать строку в кодировке UTF-8. Или я что-то упускаю.

Потому что функции Windows API либо Unicode (два байта), либо ANSI (один байт). UTF-8 здесь был бы неправильным выбором, потому что в основном он содержит один байт на символ, но для символов выше базы ASCII он использует два или более байта.

В противном случае эквивалентом вашего старого кода в Unicode Delphi было бы:

var
  UnicodeStr: string;
  UTF8Str: string;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;

WideString и строка (UnicodeString) похожи, но новая UnicodeString работает быстрее, потому что она подсчитывается по ссылкам, а WideString - нет.

Ваш код был неправильным, потому что строка UTF-8 имеет переменное количество байтов на символ. «A» хранится как один байт. Просто байтовый код ASCII. «ü», с другой стороны, будет храниться как два байта. И поскольку вы затем используете PWideChar, функция всегда ожидает два байта на символ.

Есть еще одно отличие. В более старых версиях Delphi (ANSI) Utf8String был просто AnsiString. В версиях Unicode Delphi Utf8String - это строка с кодовой страницей UTF-8 за ней. Так что ведет себя иначе.

Старый код по-прежнему будет работать правильно:

var
  UnicodeStr: WideString;
  UTF8Str: WideString;
begin
  UnicodeStr:='some unicode text';
  UTF8Str:=UTF8Encode(UnicodeStr);
  Windows.SomeFunction(PWideChar(UTF8Str), ...)
end;

Он будет действовать так же, как в Delphi 2007. Так что, возможно, у вас есть проблема в другом месте.

Мик, ты прав. Компилятор выполняет некоторую дополнительную работу за кулисами. Так что, чтобы избежать этого, вы можете сделать что-то вроде этого:

var
  UTF8Str: AnsiString;
  UnicodeStr: WideString;
  TempString: RawByteString;
  ResultString: WideString;
begin
  UnicodeStr := 'some unicode text';
  TempString := UTF8Encode(UnicodeStr);
  SetLength(UTF8Str, Length(TempString));
  Move(TempString[1], UTF8Str[1], Length(UTF8Str));
  ResultString := UTF8Str;
end;

Я проверил, и он работает точно так же.Поскольку я перемещаю байты непосредственно в памяти, преобразование кодовой страницы в фоновом режиме не выполняется. Я уверен, что это можно сделать с большей элегантностью, но дело в том, что я вижу в этом путь к тому, чего вы хотите достичь.

3
ответ дан 4 December 2019 в 13:00
поделиться

Какой вызов Windows API хочет, чтобы вы передали строку UTF-8? Это либо строка ANSI, либо широкая строка (функции A или W). Широкие строки имеют два байта на символ, а строки UTF-8 имеют один (или несколько, если вы за пределами первые 128 символов ASCII).

UTF-8 в Widestring просто не имеет смысла. Когда действительно есть функция Windows, которой нужен указатель на строку UTF-8, yo Вы, вероятно, должны передать это в PAnsiChar.

0
ответ дан 4 December 2019 в 13:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: