Има ли начин да видите дали даден знак използва 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 байта, въпреки че след като стигне до db, ще използва само 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, т.е.: if TCharacter.IsLatin1(c) then - 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 байта, в зависимост от знака. Можете да видите диаграма в Wikipedia за това как са картографирани диапазоните.

Ако обаче изобщо не променяте схемата на базата данни, това трябва да означава едно от трите неща:

  1. В момента съхранявате всичко по двоичен начин, вместо по текстов начин (обикновено не е добър избор)
  2. Базата данни вече съхранява Unicode и преброени знаци, а не байтове (в противен случай ще имате проблема сега, още повече в случай на букви с ударения)
  3. Базата данни се съхранява в еднобайтова кодова страница, като например Windows-1252, което ви пречи изобщо да съхранявате Unicode данни (което го прави непроблемно, тъй като знаците ще се съхраняват по същия начин както преди, въпреки че не можете да използвате на 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, така че проверката винаги ще връща true. - 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 знак или дали изобщо е знак по този въпрос. И така, какъв е въпросът ви отново? И защо трябва да знаете? Предполагам, че вие ​​не сте разбрали уникод или аз не съм разбрал въпроса ви.

person Lars Truijens    schedule 10.10.2008