уникален ли е item.ID за елементите?

person hkBattousai    schedule 28.09.2012    source източник
comment
Каква ОС? Някои са много по-хубави от други...   -  person BoBTFish    schedule 28.09.2012


Отговори (5)


Първо се нуждаете от по-добро разбиране на Unicode. Конкретните отговори на вашите въпроси са в долната част.

Концепции

Имате нужда от по-нюансиран набор от концепции, отколкото се изисква за много проста работа с текст, както се преподава във въвеждащите курсове по програмиране.

  • байт
  • кодова единица
  • кодова точка
  • абстрактен характер
  • характер, възприеман от потребителя

Байтът е най-малката адресируема единица памет. Днес обикновено 8 бита, способни да съхраняват до 256 различни стойности. По дефиниция char е един байт.

Кодовата единица е най-малката единица данни с фиксиран размер, използвана за съхраняване на текст. Когато наистина не ви интересува съдържанието на текста и просто искате да го копирате някъде или да изчислите колко памет използва текстът, тогава ви е грижа за кодовите единици. В противен случай кодовите единици не са много полезни.

Кодовата точка представлява отделен член на набор от знаци. Каквито и „символи“ да има в набора от знаци, на всички им е присвоен уникален номер и всеки път, когато видите кодиран конкретен номер, тогава знаете с кой член на набора от знаци имате работа.

Абстрактният знак е обект със значение в езикова система и е различен от неговото представяне или от всички кодови точки, присвоени на това значение.

Героите, възприемани от потребителя, са това, което звучат; това, което потребителят мисли за символ в каквато и езикова система да използва.

В старите времена char представляваше всички тези неща: char по дефиниция е байт, в char* низове кодовите единици са chars, наборите от символи бяха малки, така че 256-те стойности, представяни от char, бяха достатъчно, за да представят всеки член, и езиковите системи, които се поддържаха, бяха прости, така че членовете на наборите от знаци най-вече представляваха знаците, които потребителите искаха да използват директно.

Но тази проста система с char, представляваща почти всичко, не беше достатъчна, за да поддържа по-сложни системи.


Първият възникнал проблем беше, че някои езици използват много повече от 256 знака. Така бяха въведени „широки“ знаци. Широките знаци все още използват един тип за представяне на четири от горните концепции, кодови единици, кодови точки, абстрактни знаци и знаци, възприемани от потребителя. Широките знаци обаче вече не са единични байтове. Смята се, че това е най-простият метод за поддържане на големи набори от символи.

Кодът може да е почти същият, с изключение на това, че ще работи с широки знаци вместо char.

Оказва се обаче, че много езикови системи не са толкова прости. В някои системи има смисъл всеки символ, възприет от потребителя, да не бъде непременно представен от единичен абстрактен знак в набора от знаци. В резултат на това текстът, използващ набора от знаци Unicode, понякога представя възприемани от потребителя знаци, използвайки множество абстрактни знаци, или използва един абстрактен знак за представяне на множество възприемани от потребителя знаци.

Широките символи имат друг проблем. Тъй като те увеличават размера на кодовата единица, те увеличават пространството, използвано за всеки знак. Ако някой желае да работи с текст, който може да бъде адекватно представен от еднобайтови кодови единици, но трябва да използва система от широки знаци, тогава количеството на използваната памет е по-голямо, отколкото би било в случая с еднобайтови кодови единици. Поради това беше желателно широките символи да не са твърде широки. В същото време широките знаци трябва да са достатъчно широки, за да предоставят уникална стойност за всеки член на набора от знаци.

В момента Unicode съдържа около 100 000 абстрактни знака. Оказва се, че това изисква широки знаци, които са по-широки, отколкото повечето хора искат да използват. В резултат на това система от широки символи; където кодови единици, по-големи от един байт, се използват за директно съхраняване на стойности на кодови точки, се оказва нежелателно.

И така, за да обобщим, първоначално не е имало нужда да се прави разлика между байтове, кодови единици, кодови точки, абстрактни знаци и знаци, възприемани от потребителя. С времето обаче стана необходимо да се прави разлика между всяко от тези понятия.


Кодировки

Преди горното, текстовите данни бяха лесни за съхранение. Всеки възприет от потребителя знак съответства на абстрактен знак, който има стойност на кодова точка. Имаше достатъчно малко знаци, че 256 стойности бяха достатъчно. Така че човек просто съхранява номерата на кодовите точки, съответстващи на желаните знаци, възприемани от потребителя, директно като байтове. По-късно, с широки знаци, стойностите, съответстващи на възприеманите от потребителя знаци, се съхраняват директно като цели числа с по-големи размери, например 16 бита.

Но тъй като съхраняването на Unicode текст по този начин би използвало повече памет, отколкото хората са готови да похарчат (три или четири байта за всеки знак), Unicode „кодировките“ съхраняват текст не чрез директно съхраняване на стойностите на кодовите точки, а чрез използване на обратима функция за изчисляване на някои брой стойности на кодова единица, които да се съхраняват за всяка кодова точка.

Кодирането UTF-8, например, може да вземе най-често използваните кодови точки на Unicode и да ги представи с помощта на единична, еднобайтова кодова единица. По-рядко срещаните кодови точки се съхраняват с помощта на две еднобайтови кодови единици. Кодовите точки, които все още са по-рядко срещани, се съхраняват с помощта на три или четири кодови единици.

Това означава, че обичайният текст обикновено може да се съхранява с UTF-8 кодиране, като се използва по-малко памет от 16-битовите символни схеми, но също така, че съхранените числа не отговарят непременно директно на стойностите на кодовата точка на абстрактните знаци. Вместо това, ако трябва да знаете какви абстрактни знаци се съхраняват, трябва да „декодирате“ съхранените кодови единици. И ако трябва да знаете знаците, възприемани от потребителя, трябва допълнително да конвертирате абстрактните знаци в знаци, възприемани от потребителя.

Има много различни кодировки и за да конвертирате данни с помощта на тези кодировки в абстрактни знаци, трябва да знаете правилния метод за декодиране. Съхранените стойности на практика са безсмислени, ако не знаете какво кодиране е използвано за преобразуване на стойностите на кодовите точки в кодови единици.


Важно значение на кодирането е, че трябва да знаете дали определени манипулации на кодирани данни са валидни или имат смисъл.

Например, ако искате да получите „размера“ на низ, броите ли байтове, кодови единици, абстрактни знаци или знаци, възприети от потребителя? std::string::size() брои кодови единици и ако имате нужда от различен брой, тогава трябва да използвате друг метод.

Като друг пример, ако разделите кодиран низ, трябва да знаете дали го правите по такъв начин, че резултатът да е все още валиден в това кодиране и че значението на данните не се е променило неволно. Например можете да разделите кодови единици, които принадлежат към една и съща кодова точка, като по този начин създадете невалидно кодиране. Или можете да разделите между кодови точки, които трябва да се комбинират, за да представят възприет от потребителя символ и по този начин да произведете данни, които потребителят ще види като неправилни.

Отговори

Днес char и wchar_t могат да се считат само за кодови единици. Фактът, че char е само един байт, не му пречи да представлява кодови точки, които отнемат два, три или четири байта. Просто трябва да използвате две, три или четири chars последователно. Ето как UTF-8 трябваше да работи. По същия начин платформи, които използват два байта wchar_t за представяне на UTF-16, просто използват два wchar_t подред, когато е необходимо. Действителните стойности на char и wchar_t не представляват индивидуално Unicode кодови точки. Те представляват стойности на кодови единици, които са резултат от кодирането на кодовите точки. напр. Кодовата точка на Unicode U+0400 е кодирана в две кодови единици в UTF-8 -> 0xD0 0x80. Кодовата точка на Unicode U+24B62 по подобен начин се кодира в четири кодови единици 0xF0 0xA4 0xAD 0xA2.

Така че можете да използвате std::string за съхраняване на UTF-8 кодирани данни.

В Windows main() поддържа не само ASCII, но каквото и да е системното char кодиране. За съжаление Windows не поддържа UTF-8 като системно char кодиране по начина, по който го правят другите платформи, така че сте ограничени до наследени кодировки като cp1252 или каквото и да е конфигурирано да използва вашата система. Можете обаче да използвате извикване на Win32 API за директен достъп до параметрите на командния ред UTF-16, вместо да използвате параметри main()s argc и argv. Вижте GetCommandLineW() и < a href="https://msdn.microsoft.com/en-us/library/windows/desktop/bb776391(v=vs.85).aspx" rel="noreferrer">CommandLineToArgvW.

Параметърът argv на wmain() напълно поддържа Unicode. 16-битовите кодови единици, съхранявани в wchar_t на Windows, са UTF-16 кодови единици. Windows API използва UTF-16 първоначално, така че е доста лесно да се работи с него в Windows. wmain() обаче е нестандартен, така че разчитането на това няма да бъде преносимо.

person bames53    schedule 28.09.2012

Windows използва UTF-16. Всяка кодова точка в диапазона от U+0000 до U+D7FF и U+E000 до U+FFFF ще се съхранява директно; всички извън тези диапазони ще бъдат разделени на две 16-битови стойности според UTF-16 правилата за кодиране.

Например 0x24B62 ще бъде кодиран като 0xd892,0xdf62.

Можете да преобразувате низовете, за да работите с тях по какъвто начин желаете, но API на Windows все пак ще иска и доставя UTF-16, така че това вероятно ще бъде най-удобното.

person Mark Ransom    schedule 28.09.2012

Размерът и значението на wchar_t се определят от изпълнението. В Windows той е 16-битов, както казвате, на Unix-подобни системи често е 32-битов, но не винаги.

Що се отнася до този въпрос, на компилатора е разрешено да прави собствените си неща и да избира различен размер за wchar_t от това, което системата казва - той просто няма да бъде ABI-съвместим с останалата част от системата.

C++11 предоставя std::u32string, което е за представяне на низове от кодови точки на Unicode. Вярвам, че достатъчно новите компилатори на Microsoft го включват. Има донякъде ограничена употреба, тъй като системните функции на Microsoft очакват 16-битови широки знаци (известен още като UTF-16le), а не 32-битови уникод кодови точки (известен още като UTF-32, UCS-4).

Все пак споменавате UTF-8: UTF-8 кодирани данни могат да се съхраняват в обикновен std::string. Разбира се, тъй като това е кодиране с променлива дължина, не можете да получите достъп до кодови точки на unicode по индекс, можете да получите достъп само до байтовете по индекс. Но обикновено бихте написали кода си така, че да не се нуждаете от достъп до кодови точки по индекс така или иначе, дори ако използвате u32string. Unicode кодовите точки не съответстват 1-1 с печатни знаци ("графеми") поради съществуването на комбиниращи знаци в Unicode, така че много от малките трикове, които играете с низове, когато се учите да програмирате (обръщане, търсене на поднизове) не работете толкова лесно с Unicode данни, независимо в какво ги съхранявате.

Героят ???? е, както казвате, Ⓐ2. Той е UTF-8 кодиран като поредица от четири байта, а не три: F0 A4 AD A2. Преводът между UTF-8 кодирани данни и unicode кодови точки е усилие (разбира се, не е голямо усилие и библиотечните функции ще го направят вместо вас). Най-добре е да разглеждате „кодирани данни“ и „уникод данни“ като отделни неща. Можете да използвате каквото и да е представяне, което намерите за най-удобно до момента, в който трябва (например) да изобразите текста на екрана. В този момент трябва да го (пре)кодирате до кодиране, което вашата изходна дестинация разбира.

person Steve Jessop    schedule 28.09.2012
comment
(винаги?) Не. AIX използва 16-битов wchar_t и UTF-16, например. - person bames53; 28.09.2012
comment

разширяване на отговора на designcise... трябва да използвате e.stopPropagation(), за да спрете избухването на събитието

$('li img').on('click',function(e){
    e.stopPropagation();
    alert('img clicked');
});

тук jsfiddle http://jsfiddle.net/hbGRS/

- person Captain Obvlious; 28.09.2012

В стандартния C++ имаме char и wchar_t за съхраняване на знаци? char може да съхранява стойности между 0x00 и 0xFF. И wchar_t може да съхранява стойности между 0x0000 и 0xFFFF

Не точно:

sizeof(char)     == 1   so 1 byte per character.
sizeof(wchar_t)  == ?   Depends on your system 
                        (for unix usually 4 for Windows usually 2).

Unicode символите заемат до 4-байтово пространство.

Не точно. Unicode не е кодиране. Unicode е стандарт, който определя какво представлява всяка кодова точка и кодовите точки са ограничени до 21 бита. Първите 16 бита определят позицията на знака в кодова равнина, докато следващите 5 бита определят на коя равнина е символът.

Има няколко unicode кодировки (UTF-8, UTF-16 и UTF-32 са най-често срещаните) това е начинът, по който съхранявате знаците в паметта. Има практически разлики между трите.

    UTF-8:   Great for storage and transport (as it is compact)
             Bad because it is variable length
    UTF-16:  Horrible in nearly all regards
             It is always large and it is variable length
             (anything not on the BMP needs to be encoded as surrogate pairs)
    UTF-32:  Great for in memory representations as it is fixed size
             Bad because it takes 4 bytes for each character which is usually overkill

Лично аз използвам UTF-8 за транспорт и съхранение и UTF-32 за представяне на текст в паметта.

person Martin York    schedule 28.09.2012
comment
И какво използвате, за да представите последователност от групи графеми? ;-стр - person Steve Jessop; 28.09.2012
comment
@SteveJessop: Да, клъстерите на графема (трудна за изписване дума) всъщност поставят множество глифове заедно на едно и също място и представляват панел. - person Martin York; 28.09.2012
comment
За всеки, който гледа с учудване -- проблемът е, че напълно общата обработка на unicode текст, например възможността за обръщане на низ или отпечатване само на първите 10 знака, всъщност изисква третиране на UTF-32 като кодиране с променлива дължина. - person Steve Jessop; 28.09.2012

char и wchar_t не са единствените типове данни, използвани за текстови низове. C++11 въвежда нови типове данни char16_t и char32_t и съответните STL std::u16string и std::u32string типови дефиниции на std::basic_string, за да се справи с неяснотата на типа wchar_t, който има различни размери и кодировки на различни платформи. wchar_t е 16-битов на някои платформи, подходящ за UTF-16 кодиране, но е 32-битов на други платформи, вместо това подходящ за UTF-32 кодиране. char16_t е конкретно 16-битов и UTF-16, а char32_t е конкретно 32-битов и UTF-32, на всички платформи.

person Remy Lebeau    schedule 03.10.2012