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.
Ответы
Ответ 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;