Строку в массив байтов в UTF-8?

Как преобразовать WideString (или другую длинную строку) в массив байтов в UTF-8?

6 ответов


такая функция сделает то, что вам нужно:

function UTF8Bytes(const s: UTF8String): TBytes;
begin
  Assert(StringElementSize(s)=1);
  SetLength(Result, Length(s));
  if Length(Result)>0 then
    Move(s[1], Result[0], Length(s));
end;

вы можете вызвать его с любым типом строки, и RTL преобразует из кодировки строки, которая передается в UTF-8. Поэтому не обманывайте себя, думая, что вы должны преобразовать в UTF-8 перед вызовом, просто передайте любую строку и позвольте RTL делать работу.

после этого это довольно стандартная копия массива. Обратите внимание на утверждение, которое явно вызывает предположение о размере строкового элемента для кодированного UTF-8 строка.

Если вы хотите получить нулевой Терминатор, вы напишете его так:

function UTF8Bytes(const s: UTF8String): TBytes;
begin
  Assert(StringElementSize(s)=1);
  SetLength(Result, Length(s)+1);
  if Length(Result)>0 then
    Move(s[1], Result[0], Length(s));
  Result[high(Result)] := 0;
end;

можно использовать TEncoding.UTF8.GetBytes в SysUtils.pas


если вы используете Delphi 2009 или более позднюю версию (версии Unicode), преобразование WideString в UTF8String-это простая инструкция присваивания:

var
  ws: WideString;
  u8s: UTF8String;

u8s := ws;

компилятор вызовет правильную библиотечную функцию для преобразования, потому что он знает, что значения типа UTF8String имеют "кодовую страницу"CP_UTF8.

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

вы также можете написать свою собственную функцию преобразования с помощью Windows API:

function CustomUtf8Encode(const ws: WideString): UTF8String;
var
  n: Integer;
begin
  n := WideCharToMultiByte(cp_UTF8, 0, PWideChar(ws), Length(ws), nil, 0, nil, nil);
  Win32Check(n <> 0);
  SetLength(Result, n);
  n := WideCharToMultiByte(cp_UTF8, 0, PWideChar(ws), Length(ws), PAnsiChar(Result), n, nil, nil);
  Win32Check(n = Length(Result));
end;

много времени вы можете просто использовать UTF8String в качестве массива, но если вам действительно нужен массив байтов, вы можете использовать функции Дэвида и Космина. Если вы пишете свою собственную функцию преобразования символов, вы можете пропустить UTF8String и перейти непосредственно к массиву байтов; просто измените тип возврата на TBytes или array of Byte. (Вы также можете увеличить длину на единицу, если вы хотите, чтобы массив был null-terminated. SetLength сделает это для строки неявно, но для массива.)

если у вас есть какой-то другой тип строки, который не является ни WideString, UnicodeString, ни UTF8String, то способ преобразовать его в UTF-8-это сначала преобразовать его в WideString или UnicodeString, а затем преобразовать его обратно в UTF-8.


var S: UTF8String;
    B: TBytes;

begin
  S := 'Șase sași în șase saci';
  SetLength(B, Length(S)); // Length(s) = 26 for this 22 char string.
  CopyMemory(@B[0], @S[1], Length(S));
end.

в зависимости от того, для чего вам нужны байты, вы можете включить нулевой Терминатор.

для производственного кода убедитесь, что вы проверяете пустую строку. Добавление требуемого 3-4 LOC просто затруднит чтение образца.


У меня есть следующие две подпрограммы (исходный код можно скачать здесь -http://www.csinnovations.com/framework_utilities.htm):

функция CsiBytesToStr(const pInData: TByteDynArray; pStringEncoding: TECsiStringEncoding; pIncludesBom: Boolean): string;

функция CsiStrToBytes(const pInStr: строка; pStringEncoding: TECsiStringEncoding; pIncludeBom: Boolean): TByteDynArray;


widestring - > UTF8:

http://www.freepascal.org/docs-html/rtl/system/utf8decode.html

противоположную:

http://www.freepascal.org/docs-html/rtl/system/utf8encode.html

обратите внимание, что назначение widestring ansistring в системе pre D2009 (включая текущий бесплатный Pascal) преобразуется в локальную кодировку ansi, искажая символы.

для части TBytes см. замечание Роба Кеннеди сверху.