Есть ли способ узнать, использует ли символ 1 или 2 байта в Delphi 2009?

Delphi 2009 изменил свой строковый тип, чтобы использовать 2 байта для представления символа, что позволяет поддерживать наборы символов Unicode. Теперь, когда вы получаете sizeof (string), вы получаете length (String) * sizeof (char). Sizeof (char) в настоящее время составляет 2.

Что меня интересует, так это то, знает ли кто-нибудь способ, с помощью которого можно по каждому символу узнать, поместится ли он в один байт, например, узнать, является ли символ ascii или Unicode.

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

Нам нужно иметь возможность установить ограничения заранее и в идеале (поскольку у нас большая установленная база) без необходимости изменять базу данных. Если строковое поле допускает 12 байтов, в delphi 2009 строка длиной 7 всегда будет отображаться как использующая 14 байтов, даже если после того, как она попала в базу данных, она будет использовать только 7, если ascii, или 14, если двухбайтный, или где-то посередине, если смесь.


person Toby Allen    schedule 10.10.2008    source источник


Ответы (7)


Вы можете проверить значение символа:

if ord(c) < 128 then
    // is an ascii character
person Greg Hewgill    schedule 10.10.2008
comment
Поскольку вы все равно используете D2009, посмотрите на новый класс TCharacter, то есть: если TCharacter.IsLatin1 (c), то - person Remy Lebeau; 06.06.2009
comment
@ RemyLebeau-TCharacter.IsLatin недоступен в Delphi XE7. Кто-нибудь знает его замену? - person Z80; 17.08.2017

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

Количество байтов, которое будет использовать ваша строка, полностью зависит от кодировки символов, в которой она будет храниться. Если это UTF-16, тип строки по умолчанию в Delphi, то он всегда будет 2 байта на символ, за исключением суррогатов.

Однако наиболее вероятной кодировкой, если в базе данных используется кодировка Unicode, является UTF-8. Это кодировка переменной длины: для символов может потребоваться от 1 до 4 байтов, в зависимости от символа. Вы можете увидеть в Википедии диаграмму того, как отображаются диапазоны.

Однако, если вы вообще не меняете схему базы данных, это должно означать одно из трех:

  1. В настоящее время вы храните все в двоичном виде, а не в текстовом (обычно не лучший выбор)
  2. В базе данных уже хранятся символы Unicode и подсчитанные символы, а не байты (в противном случае у вас возникла бы проблема, особенно в случае букв с диакритическими знаками)
  3. База данных хранится в однобайтовой кодовой странице, такой как Windows-1252, что не позволяет вам вообще хранить данные Unicode (что делает это не проблемой, потому что символы будут храниться так же, как и раньше, хотя вы не можете использовать Юникода)

Я не знаком с Oracle, но если вы посмотрите на MSSQL, у них есть два разных типа данных: varchar и nvarchar. Varchar считает в байтах, а nvarchar - в символах, поэтому подходит для Unicode. В MySQL, с другой стороны, есть только varchar, и он всегда считается в символах (начиная с версии 4.1). Поэтому вам следует проверить документацию Oracle и схему своей базы данных, чтобы получить решительный ответ о том, является ли это проблемой вообще.

person Michael Madsen    schedule 10.10.2008

Если вы не хотите использовать Unicode в Delphi 2009, вы можете использовать тип AnsiString. Но зачем тебе.

Громоздким, но действенным тестом может быть:

function IsAnsi(const AString: string): Boolean;
var
  tempansi : AnsiString;
  temp : string;
begin
  tempansi := AnsiString(AString);
  temp := tempansi;
  Result := temp = AString;
end;
person Toon Krijthe    schedule 10.10.2008
comment
Я думаю, что AnsiString следует принудительно привязать к определенной кодовой странице, такой как AnsiString (CP_UTF8). - person skamradt; 10.10.2008
comment
@skamradt Разве AnsiString (CP_UTF8) не уничтожит всю цель функции? Все строки Unicode также могут быть представлены в UTF-8, поэтому проверка всегда будет возвращать истину. - person Otherside; 17.10.2008

Вы можете использовать функцию StringElementSize, чтобы узнать, является ли строка Unicode или ANSI. Чтобы проверить, является ли символ ANSI, используйте функцию класса TCharacter.IsAnsi в модуле Character.pas.

person vcldeveloper    schedule 24.12.2008

Вы ответили, что действительно хотите узнать, сколько байтов займет ваша строка.

Как насчет преобразования в UTF8String? Символы Ansi занимают 1 байт. Имейте в виду, что в UTF-8 символы Unicode могут занимать более 2 байтов.

person Bruce McGee    schedule 07.11.2008

Поскольку с AnsiString 1 char = 1 байт и с Unicode String 1 char = 2 байта, простой тест для выполнения - IsAnsiString: = sizeof (aString) = length (aString);

person Community    schedule 21.10.2008
comment
Если я не ошибаюсь, SizeOf (String) вернет 4 во всех 32-битных версиях Delphi, потому что String (AnsiString или UnicodeString) является типом указателя. Таким образом SizeOf () вернет размер указателя. Length (String) возвращает количество символов, поэтому эта ваша проверка не сработает. - person PatrickvL; 11.11.2008

Символ ASCII всегда умещается в одном байте. Вы не можете сказать то же самое для символа Юникода, поскольку это зависит от того, как он закодирован. Вы не можете увидеть из одного байта, является ли он символом ASCII или Unicode или вообще является ли это символом в этом отношении. Итак, в чем ваш вопрос еще раз? А зачем вам это знать? Я предполагаю, что вы неправильно поняли Unicode или я неправильно понял ваш вопрос.

person Lars Truijens    schedule 10.10.2008