Строка в байтовый массив в UTF-8? - PullRequest
8 голосов
/ 08 марта 2011

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

Ответы [ 6 ]

12 голосов
/ 08 марта 2011

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

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;
8 голосов
/ 08 марта 2011

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

5 голосов
/ 08 марта 2011

Если вы используете 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. (Вы также можете увеличить длину на единицу, если хотите, чтобы массив заканчивался нулем. SetLength будет делать это со строкой неявно, но с массивом.)

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

4 голосов
/ 08 марта 2011
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.

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

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

1 голос
/ 09 марта 2011

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

функция CsiBytesToStr (const pInData: TByteDynArray; pStringEncoding: TECsiStringEncoding; pIncludesBom: Boolean): строка;

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

0 голосов
/ 09 марта 2011

Widestring -> UTF8:

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

наоборот:

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

Обратите внимание, что назначение самой широкой строки для анстистри в системе, предшествующей D2009 (включая текущий Free Pascal), преобразует в локальную кодировку ANSI, искажая символы.

Для части TBytes см. Замечание Роба Кеннеди выше.

...