Delphi XE - RawByteString против AnsiString - PullRequest
7 голосов
/ 19 мая 2011

У меня был похожий вопрос к этому здесь: Delphi XE - я должен использовать String или AnsiString? .Решив, что в моей (большой) библиотеке можно использовать строки ANSI, я понял, что на самом деле могу использовать RawByteString вместо ANSI.Поскольку я смешиваю строки UNICODE со строками ANSI, мой код теперь имеет довольно мало мест, где он выполняет преобразования между ними.Однако, похоже, что если я использую RawByteString, я избавлюсь от этих преобразований.

Пожалуйста, дайте мне знать ваше мнение об этом.
Спасибо.


Обновление:
Это кажется разочаровывающим.Похоже, что компилятор все еще выполняет преобразование из RawByteString в строку.

procedure TForm1.FormCreate(Sender: TObject);
var x1, x2: RawByteString;
    s: string;
begin
  x1:= 'a';
  x2:= 'b';
  x1:= x1+ x2;
  s:= x1;              {      <------- Implicit string cast from 'RawByteString' to 'string'     }
end;

Я думаю, что он выполняет некоторые внутренние операции (например, копирование данных), и мой код не будет намного быстрее, и мне все равно придетсядобавьте много типов в мой код, чтобы заставить компилятор замолчать.

Ответы [ 2 ]

12 голосов
/ 20 мая 2011

RawByteString - это AnsiString без кодовой страницы, установленной по умолчанию.

Когда вы назначите другую string этой переменной RawByteString, вы скопируете кодовую страницу источника string.И это будет включать в себя преобразование.Извините.

Но есть еще один способ использования RawByteString, который предназначен для хранения простого байтового содержимого (например, содержимого поля BLOB базы данных, как array of byte)

Подводя итог:

  • RawByteString следует использовать в качестве параметра "независимой от кодовой страницы" для метода или функции;
  • RawByteString можно использовать в качестве типа переменной для хранения некоторых данных BLOB.

Если вы хотите уменьшить конверсию и предпочитаете использовать в своем приложении 8-битный символ string, вам лучше:

  • Не использовать универсальный *Тип 1028 *, который будет зависеть от текущей системной кодовой страницы и по которой вы будете терять данные;
  • Положитесь на кодировку UTF-8, т. Е. Некоторую 8-битную кодовую страницу / кодировку, которая не потеряет никаких данных при преобразовании из или в UnicodeString;
  • Не позволяйте компиляторупокажите предупреждения о неявных преобразованиях: все преобразования должны быть сделаны явными;
  • Используйте свой собственный выделенный набор функций для обработки содержимого UTF-8.

Этоименно то, что мы сделали для нашей структуры.Мы хотели использовать UTF-8 в его ядре, потому что:

  • Мы полагаемся на кодирование JSON в кодировке UTF-8 для передачи данных;
  • Потребление памяти будет меньше;
  • Используемый SQLite3 движок будет хранить текст как UTF-8 в своем файле базы данных;
  • Мы хотели получить способ обработки текста Unicode без потери данных во всех версиях Delphi (из Delphi).От 6 до XE), и WideString не был выбран, потому что он очень медленный, и у вас та же проблема неявных преобразований.

Но, чтобы достичь максимальной скорости, мы пишемнекоторые оптимизированные функции для обработки нашего пользовательского типа строки:

  {{ RawUTF8 is an UTF-8 String stored in an AnsiString
    - use this type instead of System.UTF8String, which behavior changed
     between Delphi 2009 compiler and previous versions: our implementation
     is consistent and compatible with all versions of Delphi compiler
    - mimic Delphi 2009 UTF8String, without the charset conversion overhead
    - all conversion to/from AnsiString or RawUnicode must be explicit }
{$ifdef UNICODE} RawUTF8 = type AnsiString(CP_UTF8); // Codepage for an UTF8string
{$else}          RawUTF8 = type AnsiString; {$endif}

/// our fast RawUTF8 version of Trim(), for Unicode only compiler
// - this Trim() is seldom used, but this RawUTF8 specific version is needed
// by Delphi 2009/2010/XE, to avoid two unnecessary conversions into UnicodeString
function Trim(const S: RawUTF8): RawUTF8;

/// our fast RawUTF8 version of Pos(), for Unicode only compiler
// - this Pos() is seldom used, but this RawUTF8 specific version is needed
// by Delphi 2009/2010/XE, to avoid two unnecessary conversions into UnicodeString
function Pos(const substr, str: RawUTF8): Integer; overload; inline;

И мы зарезервировали тип RawByteString для обработки данных BLOB:

{$ifndef UNICODE}
  /// define RawByteString, as it does exist in Delphi 2009/2010/XE
  // - to be used for byte storage into an AnsiString
  // - use this type if you don't want the Delphi compiler not to do any
  // code page conversions when you assign a typed AnsiString to a RawByteString,
  // i.e. a RawUTF8 or a WinAnsiString
  RawByteString = AnsiString;
  /// pointer to a RawByteString
  PRawByteString = ^RawByteString;
{$endif}

/// create a File from a string content
// - uses RawByteString for byte storage, thatever the codepage is
function FileFromString(const Content: RawByteString; const FileName: TFileName;
  FlushOnDisk: boolean=false): boolean;

Исходный код доступен в нашемхранилище .В этом блоке функции, связанные с UTF-8, были глубоко оптимизированы, и версия на паскале, и версия asm для лучшей скорости.Иногда мы перегружали функции по умолчанию (например, Pos), чтобы избежать преобразования, или Подробнее о том, как мы обрабатывали текст в платформе, можно узнать здесь: .

Последнее слово:

Если вы уверены , что в вашем приложении будет только 7-битное содержимое (без выделенных символов), вы можете использовать в своей программе тип AnsiString по умолчанию.Но в этом случае вам лучше добавить модуль AnsiStrings в ваше предложение uses, чтобы иметь перегруженные строковые функции, которые позволят избежать большинства нежелательных преобразований.

10 голосов
/ 20 мая 2011

RawByteString все еще"AnsiString." Лучше всего его описать как «универсальный получатель», что означает, что он будет принимать любую кодовую страницу исходной строки в точке назначения без принудительного преобразования кодовой страницы. RawByteString предназначался для использования только в качестве параметра функции, чтобы, как вы обнаружили, вы не подвергались преобразованию между AnsiStrings с различным сходством кодовых страниц при вызове служебных функций, которые принимают AnsiStrings.

Однако в приведенном выше случае вы присваиваете UnicodeString то, что по сути является AnsiString, которое будет выполнять преобразование. Он должен выполнить преобразование, потому что полезная нагрузка RawByteString состоит из 8-битных символов, тогда как строка (UnicodeString) имеет полезную нагрузку из 16-битных символов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...