Подтвердить что ты не робот

Delphi WideString и Delphi 2009+

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

  • Delphi 2005 WideString - это тот же тип, что и Delphi 2010 String

  • Delphi 2005 WideString char, а также Delphi 2010 String char гарантируется всегда размером 2 байта.

При использовании всех форматов Unicode я не хочу, чтобы один из символов в моей строке внезапно попадал в 3 байта или что-то в этом роде.

Изменить: Нашел это: "Я действительно сказал UnicodeString, а не WideString. WideString все еще существует и не изменяется. WideString выделяется диспетчером памяти Windows и должен использоваться для взаимодействия с объектами COM WideString сопоставляет непосредственно с BSTR-типом в COM." на http://www.micro-isv.asia/2008/08/get-ready-for-delphi-2009-and-unicode/

Теперь я еще более смущен. Итак, Delphi 2010 WideString отличается от Delphi 2005 WideString? Должен ли я использовать UnicodeString вместо этого?

Изменить 2: Нет типа UnicodeString в Delphi 2005. FML.

4b9b3361

Ответ 1

Для вашего первого вопроса: WideString не совсем тот же тип, что и D2010 string. WideString - это тот же тип COM BSTR, что и всегда. Он управляется Windows, без подсчета ссылок, поэтому он копирует весь BSTR каждый раз, когда вы его передаете.

UnicodeString, который по умолчанию является строкой в D2009 и включен, является в основном версией AnsiString UTF-16, которую все мы знаем и любим. Он получил счетчик ссылок и управляется компилятором Delphi.

Во втором случае тип char по умолчанию теперь WideChar, который является тем же самым символом, который всегда использовался в WideString. Это кодировка UTF-16, 2 байта на char. Если вы сохраните данные WideString в файл, вы можете без проблем загрузить его в UnicodeString. Разница между этими двумя типами связана с управлением памятью, а не с форматом данных.

Ответ 2

Как упоминалось ранее, тип данных string (фактически UnicodeString) в Delphi 2009 и выше не эквивалентен типу данных WideString в предыдущих версиях, но формат содержимого данных одинаков. Оба они сохраняют строку в UTF-16. Поэтому, если вы сохраняете текст с помощью WideString в более ранних версиях Delphi, вы должны иметь возможность правильно его читать, используя строковый тип данных в последних версиях Delphi (2009 и выше).

Следует отметить, что производительность UnicodeString намного превосходит WideString. Поэтому, если вы собираетесь использовать один и тот же исходный код как в Delphi 2005, так и в Delphi 2010, я предлагаю вам использовать псевдоним типа string с условной компиляцией в вашем коде, чтобы вы могли использовать лучшее из обоих миров:

type
  {$IFDEF Unicode}
  MyStringType = UnicodeString;
  {$ELSE}
  MyStringType = WideString;
  {$ENDIF}

Теперь вы можете использовать MyStringType в качестве типа строки в исходном коде. Если компилятор является Unicode (Delphi 2009 и выше), то ваш тип строки будет алиасом типа UnicodeString, который представлен в Delphi 2009 для хранения строк Unicode. Если компилятор не является unicode (например, Delphi 2005), тогда ваш тип строки будет псевдонимом для старого типа данных WideString. И поскольку оба они являются UTF-16, данные, сохраненные в любой из версий, должны быть правильно прочитаны другим.

Ответ 3

  • Delphi 2005 WideString имеет тот же тип, что и строка Delphi 2010

Это неверно - ex-строка Delphi 2010 содержит скрытое внутреннее поле кодовой страницы, но, вероятно, для вас это не важно.

  • Delphi 2005 WideString char, а также строка Delphi 2010 char гарантированно будет иметь размер 2 байта.

Это верно. В Delphi 2010 SizeOf (Char) = 2 (Char= WideChar).


Для строк unicode не может быть другой кодовой страницы - было введено поле кодовой страницы для создания общего двоичного формата для строк Ansi (для которых требуется поле кодовой страницы) и строки Unicode (это не нужно).

Если вы сохраняете данные WideString для потока в Delphi 2005 и загружаете одни и те же данные в строку в Delphi 2010, все должно работать нормально.

WideString = BSTR и не изменяется между Delphi 2005 и 2010

UnicodeString = WideString в Delphi 2005 (если тип UnicodeString существует в Delphi 2005 - я не знаю) UnicodeString = строка в Delphi 2009 и выше.


@Marco - строки Ansi и Unicode в Delphi 2009+ имеют общий двоичный формат (12-байтовый заголовок).

Кодовая страница UnicodeString CP_UTF16 = 1200;

Ответ 4

Правило простое:

  • Если вы хотите работать только с строками unicode внутри вашего модуля - используйте UnicodeString type (*).
  • Если вы хотите общаться с COM или с другими кросс-модульными целями, используйте тип WideString.

Вы видите, WideString - особый тип, поскольку он не является родным типом Delphi. Это псевдоним/оболочка для BSTR - тип системной строки, предназначенный для использования с COM или межмодульными сообщениями. Будучи юникодом - это просто побочный эффект.

С другой стороны, AnsiString и UnicodeString - являются родными типами Delphi, которые не имеют аналога на других языках. String является просто псевдонимом для AnsiString или UnicodeString.

Итак, если вам нужно передать строку в другой код - используйте WideString, в противном случае используйте либо AnsiString, либо UnicodeString. Простой.

P.S.

(*) Для старого Delphi - просто место

{$IFNDEF Unicode}

type
  UnicodeString = WideString;

{$ENDIF}

где-то в вашем коде. Это исправление позволит вам написать тот же код для любой версии Delphi.

Ответ 5

В то время как D2010 char всегда и ровно 2 байта, в символах UTF-16 присутствуют те же проблемы сложения и комбинирования символов, что и символы UTF-8. Вы не видите этого с узкими строками, потому что они основаны на кодировке, но с помощью строк unicode возможно (и в некоторых ситуациях общее) иметь аффективные, но невидимые символы. Примеры включают в себя знак порядка байтов (BOM) в начале файла или потока unicode, символы слева направо/справа налево и огромный диапазон сочетания акцентов. Это в основном затрагивает вопросы о том, "сколько пикселей будет шириной этой строки на экране" и "сколько букв находится в этой строке" (в отличие от "количества символов в этой строке" ), но также означает, t случайным образом измельчают символы из строки и предполагают, что они пригодны для печати. Такие операции, как "удалить последнюю букву из этого слова", становятся нетривиальными и зависят от используемого языка.

Вопрос о том, что "один из символов в моей строке внезапно имеет длину 3 байта", отражает небольшое недоверие к тому, как работает UTF. Возможно (и действительно) взять три байта в строке UTF-8, чтобы представить один печатный символ, но каждый байт будет действительным символом UTF-8. Скажем, письмо плюс два сочетания акцентов. Вы не получите символ в UTF-16 или UTF-32 длиной 3 байта, но может иметь длину 6 байтов (или 12 байтов), если он представлен с использованием трех кодовых точек в UTF-16 или UTF-32. Это приводит нас к нормализации (или нет).

Но при условии, что вы имеете дело со строками как целые вещи, все это очень просто - вы просто берете строку, записываете ее в файл, а затем читаете ее обратно. Вам не нужно беспокоиться о мелкой печати отображения строк и манипуляций, которые обрабатываются операционной системой и библиотеками. Строки. LoadFromFile (имя) и Listbox.Items.Add(строка) работают точно так же в D2010, как и в D2007, все файлы unicode прозрачны для вас как программиста.

Ответ 6

Я пишу класс, который сохранит широкие строки в двоичном файле.

Когда вы пишете класс в D2005, вы будете использовать Widestring Когда вы перейдете на D2010, Widestring будет действительным и будет работать правильно. Widestring в D2005 такая же, как WideString в D2010.

Тот факт, что String = WideString в D2010 не нужно учитывать, поскольку компилятор легко справляется с этими проблемами.

В вашей процедуре ввода для сохранения с (AString: String) требуется только одна строка, вступающая в proc

procedure SaveAStringToBIN_File(AString:String);
var wkstr : Widestring;
begin
{$IFDEF Unicode}  wkstr := AString;      
{$ELSE}           wkstr := UTF8Decode(AString);   {$ENDIF}
...
   the rest is the same saving a widestring to a file stream
  write the length (word) of string then data 

end;