Delphi WideString и Delphi 2009+ - PullRequest
       39

Delphi WideString и Delphi 2009+

13 голосов
/ 04 ноября 2010

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

  1. Delphi 2005 WideString равен точно того же типа, что и Delphi 2010 String

  2. Символ Delphi 2005 WideString, а также символ Delphi 2010 String гарантированно имеют всегда размером 2 байта.

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

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

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

Редактировать 2: В Delphi 2005 нет типа UnicodeString. FML.

Ответы [ 6 ]

12 голосов
/ 04 ноября 2010

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

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

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

4 голосов
/ 04 ноября 2010

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

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

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

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

1 голос
/ 04 ноября 2010
  1. Delphi 2005 WideString точно такого же типа, как Delphi 2010 String

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

  1. Символ Delphi 2005 WideString, а также символ Delphi 2010 String всегда будут иметь размер 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 (если в Delphi 2005 существует тип UnicodeString - я не знаю) UnicodeString = строка в Delphi 2009 и выше.


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

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

0 голосов
/ 09 декабря 2010

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

Когда вы пишете класс в 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;
0 голосов
/ 10 ноября 2010

Хотя символ D2010 всегда равен 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. Что приводит нас к нормализации (или нет).

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

0 голосов
/ 05 ноября 2010

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

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

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

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

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

P.S.

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

{$IFNDEF Unicode}

type
  UnicodeString = WideString;

{$ENDIF}

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

...