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

#delphi #unicode #delphi-2009 #character-encoding

Вопрос:

Delphi 2009 изменил тип строки, чтобы использовать 2 байта для представления символа, что позволяет поддерживать наборы символов unicode. Теперь, когда вы получаете размер(строка), вы получаете длину(строка) * размер(символ) . Размер(символ) в настоящее время равен 2.

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

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

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

Ответ №1:

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

 if ord(c) < 128 then
    // is an ascii character
 

Комментарии:

1. Поскольку вы все равно используете D2009, посмотрите на новый класс TCharacter, то есть: if TCharacter. ИсЛатин1(c), затем

2. @RemyLebeau-характерный персонаж. ИсЛатин недоступен в Delphi XE7. Кто-нибудь знает его замену?

Ответ №2:

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

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

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

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

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

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

Ответ №3:

Если вы не хотите использовать Юникод в Delphi 2009, вы можете использовать тип AnsiString. Но почему ты должен это делать?

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

 function IsAnsi(const AString: string): Boolean;
var
  tempansi : AnsiString;
  temp : string;
begin
  tempansi := AnsiString(AString);
  temp := tempansi;
  Result := temp = AString;
end;
 

Комментарии:

1. Я думаю, что регистрацию ANS следует также принудительно перенести на определенную кодовую страницу, такую как регистрация ANS(CP_UTF8).

2. @skamradt Разве регистрация(CP_UTF8) не уничтожит всю цель функции? Все строки юникода также могут быть представлены в UTF-8, поэтому проверка всегда будет возвращать значение true.

Ответ №4:

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

Ответ №5:

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

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

Ответ №6:

Поскольку при регистрации 1 символ = 1 байт и при строке Юникода 1 символ = 2 байта, простой тест для выполнения-это регистрация:= sizeof(строка)=длина(строка);

Комментарии:

1. Если я не ошибаюсь, SizeOf(Строка) вернет 4 во всех 32-разрядных версиях Delphi, потому что строка (либо AnsiString, либо UnicodeString) является типом указателя. Таким образом, функция SizeOf() вернет размер указателя. Длина(строка) возвращает количество символов, так что эта ваша проверка не сработает.

Ответ №7:

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