UTF-16
UTF-16 är 16-bitars kodningsschema med variabel längd och det använder UTF-teckenuppsättningen för teckenkodpunkter. Detta innebär att ett UTF-16-kodat tecken kommer att ha en 16-bitars kodenhet.
som vi vet att ett UTF-8-kodat tecken kan representeras i 1 till 4 kodenheter, kan ett UTF-16-tecken representeras i 1 eller 2 kodenheter. Därför kan ett UTF-16-tecken TA 16 eller 32 bitar minne baserat på dess kodpunkt.
innan vi hoppar in i UTF-16-kodningsspecifikationerna, låt oss förstå hur vi kan få UTF-16 att fungera.
eftersom vi har 16-bitars kodenhet, i teorin, kan vi koda 21-tecken från kodpunkt 0 till 65,535. Men vad händer om vi har ett tecken med kodpunkten större än 65 535? I så fall kan vi lägga till en annan kodenhet.
med den extra kodenheten kan vi koda totalt 232 tecken som är mer än 4M. men då är frågan hur en UTF-16-avkodare vet att den måste överväga 2 kodenheter för att avkoda ett tecken?
UTF-8 löste detta problem genom att ställa in initiala bitar av den första kodenheten och fortsättningskodsenheterna till vissa specifika bitvärden som en UTF-8-avkodare kan använda för att dra av hur många kodenheter ett tecken kan ta.
Vi kan göra detsamma med UTF-16-kodenheten men då måste vi offra några bitar i en kodenhet för den här funktionen. Vi kan ställa in några initiala bitar av en kodenhet till något meningsfullt värde som en UTF-16-avkodare kan förstå.
även för att ge kodenheter självsynkroniserande kraft måste en kodenhet kunna avgöra om det är den ursprungliga kodenheten eller en fortsättningskodsenhet och inte ett tecken på bara en kodenhet.
så Unicode bestämde sig för att offra de första 6 bitarna i kodenheten och lämnade endast 10 bitar för att koda kodpunkten för ett tecken per kodenhet. Om ett tecken behöver 2 kodenheter innehåller 20 bitar av minnet (av 32 bitar eller 4 byte) den faktiska kodpunktsinformationen för tecknet.
Så vad är dessa initiala bitar och hur dessa bitar gör en tand i UTF-teckenuppsättningen? Låt oss följa exemplet nedan.
1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
FIRST CODE UNIT---- SECOND CODE UNIT---
från UTF-16-standarden bör den första kodenheten börja med 110110₂ och den andra kodenheten bör börja med 110111₂. Detta hjälper en UTF-16-avkodare att förstå vilken om den första kodenheten och vilken som är den andra. Detta gör UTF-16 självsynkroniserande.
nu vad vi har 10 bitar per kodenhet att spela med, vad är det intervall vi kan spela inom? I slutändan, hur många tecken kan kodas i två kodenheter för UTF-16-kodning?
oroa dig inte, vi kommer att prata om tecken kodade i bara en kodenhet.
om du tittar på ovanstående kodenhetsmallar har vi ett intervall från 1101 1000 0000 0000₂ till 1101 1111 1111 1111₂. Det motsvarar D800 ^ till DFFF^^.
den första kodenheten har intervallet från D800 ^ till 6FFF ^ och den andra kodenheten har intervallet från DC00 ^ till DFFF^. Vi kan få dessa värden genom att vrida alla Kodpunkter bitar : på och av.
eftersom UTF-16 måste vara självsynkroniserande får Kodpunkter mellan D800^, och DFFF^, inte representera ett tecken i UTF-16. Eftersom alla UTF-kodningar följer samma UTF-teckenuppsättning begränsas dessa Kodpunkter av UTF och de tilldelas inte och kommer inte att tilldelas några tecken.
Kodpunkter mellan D800 ^ – och DFFF ^ – representerar inte några tecken, därför kallas de surrogatkodpunkter eller tillsammans kallas de också som surrogatpar⁰.
den första surrogatkodpunkten (från första kodenheten) kallas också som hög surrogat och andra kodpunkt (från andra kodenheten) kallas också som låg surrogat. Gör totalt 2048 Kodpunkter, 1024 per surrogat.
sacrib surrogat-Kodpunkter offrade sina liv så att vi kunde koda fler tecken med två kodenheter. Tänk på det!
så den stora frågan, kan vi koda ett tecken med en enda kodenhet av UTF-16? Svaret är ja. UTF – 16 är ett 16-bitars kodningsschema med variabel längd. Så betyder det att vi kan koda 21-tecken med en enda kodenhet?
svaret är nej. I teorin skulle vi kunna koda 21 x tecken med kodpunkt 0000 xnumx (0 xnumx) till FFFF XNUMX (65535 xnumx) men Kodpunkter mellan D800 xnumx och DFFF xnumx representerar inte några tecken eftersom de är reserverade.
därför är det säkert att koda tecken från 0000 till D7FF och E000 till FFFF och lämna vilka konton till 63 488 (65536-2048) tecken. Detta är bara för de tecken som kan kodas i bara en kodenhet av UTF-16.
eftersom vi har totalt 20 bitar att spela med när det gäller tecken än vad som kan kodas i 2 kodenheter av UTF-16, kan vi koda 22⁰ fler tecken, vilket är 1,048,576 tecken.
så totalt kan vi koda 1,048,576 + 63,488 vilket uppgår till 1,112,064 tecken (mer än 1Million tecken). Detta är gränsen för UTF-teckenuppsättningen. Eftersom UTF-16 kan koda dessa många tecken kan andra UTF-kodningar inte representera tecken utöver dessa.
UTF charset Code Points
eftersom vi vet att en kodpunkt är ett decimalvärde som tilldelas ett tecken, får vi (Unicode) inte tilldela en ogiltig kodpunkt till ett faktiskt tecken. Hittills är de ogiltiga kodpunkterna surrogatkodpunkter.
med bara en enda UTF-16-kodenhet kan vi koda 63 488 tecken från 0000 till D7FF och E000 till FFFF. Den sista kodpunkten är 65 535. Dessa kallas BMP-tecken (förklaras senare).
med två kodenheter av UTF-16 kan vi Koda 1 048 576 tecken. Eftersom vi inte kan börja igen från 0-värde (kodpunkt) eftersom dessa kommer efter BMP-tecken, måste vi kompensera dem med 65,536. Dessa tecken kallas kompletterande tecken (förklaras senare).
därför har det första kompletterande tecknet ett kodpunktsvärde på 65536^, vilket motsvarar 10000^^. Eftersom vi kan koda 1 048 576 tecken med två kodenheter av UTF-16 är den sista kodpunkten 1114111^, vilket motsvarar 10ffff^,.
så låt oss bryta ner saker i en enkel tabellform.
+-----------+---------------------+--------------------+
| UTF-16 CU | Code Point | |
+-----------+---------------------+--------------------+
| 1 | 0000₁₆ - D7FF₁₆ | valid |
+-----------+---------------------+--------------------+
| 1 | D800₁₆ - DFFF₁₆ | invalid(surrogate) |
+-----------+---------------------+--------------------+
| 1 | E000₁₆ - FFFF₁₆ | valid |
+-----------+---------------------+--------------------+
| 2 | 10000₁₆ - 10FFFF₁₆ | valid |
+-----------+---------------------+--------------------+
| | 110000₁₆ - FFFFFF₁₆ | unassigned |
+-----------+---------------------+--------------------+
Med denna kunskap, låt oss se hur vi kan koda vissa tecken i UTF-16. Låt oss välja ett enkelt ASCII-tecken A (kodpunkt: 41 ^ vent), ett tecken från Hindi (indiskt) språk (uttalas som Aa, kodpunkt: 906 ^ vent) och en uttryckssymbol (kallas som lyckligt ansikte, kodpunkt: 1f60a ^ vent).
som vi kan se från ovanstående tabell kan både A och bisexuell kodas i bara en kodenhet av UTF-16 eftersom deras värden är mindre än FFFF^,.
När vi måste koda ett tecken i bara en kodenhet måste vi bara konvertera kodpunkten för tecknet i ett 16-bitars binärt tal. För tecknen A är 00000000 01000001₂ UTF-16-representationen.
På samma sätt behöver vi bara konvertera dess kodpunkt 906, till ett 16-bitars binärt tal som är 00001001 00000110₂.
normalt representerar vi kodenheter av ett tecken i hexadecimala tal. Därför för tecken A är UTF-16-representationen 0041^, och på samma sätt för karaktären är UTF-16-representationen 0906^.
för teckenetubbi, saker är lite annorlunda. Dess kodpunkt är 1F60A. Om vi tittar på UTF-16-tabellen som nämns ovan måste den kodas i 2 kodenheter i UTF-16. Så hur börjar vi?
först måste vi subtrahera 10000undvit från kodpunkten. Anledningen till detta är att varje tecken som kodas i 2 kodenheter i UTF-16 har kommit efter BMP-tecknen vars sista kodpunkt är FFFF^,.för att få det faktiska värdet av bitar som används för kodning (vilket är 20 i 2 kodenheter) måste vi subtrahera 10000 ^ från kodpunkten och använda det slutliga numret för att generera dessa 20 bitar.
för att hjälpa dig att förstå bättre, kommer det första tecknet som representeras med 2 kodenheter av UTF-16 att ha alla sina 20 bitar inställda på 0. Så värdet på bitarna som används för att koda kodpunkten för detta tecken är 0. Men ändå är dess kodpunkt 10000, enligt Unicode-teckenuppsättning. Detta beror på att värdet som ges av dessa 20 bitar läggs till 10000 för att generera den slutliga kodpunkten.
som tidigare sett ser dessa 2 kodenheter ut som nedan.
1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
FIRST CODE UNIT---- SECOND CODE UNIT---
vi behöver bara fylla dessa 20 bitar (x
) med värdet mottaget från teckenkodpunkten. Kodpunkten för tecknet Macau är 1F60A. Men först måste vi subtrahera 10000undvit från det. Vi får F60A^,.
nu måste vi konvertera F60A i ett 20-bitars binärt tal och fylla de 20 bitarna i ovanstående kodenhetsmall. F60a ^ i binär är 0000111101 1000001010₂. Nu kan vi fylla dessa 20 platshållarbitar.
nedan är de slutliga kodenheterna.
1101 1000 0011 1101 1101 1110 0000 1010
0xD83D 0xDE0A
det snabba sättet att kontrollera om dessa kodenheter är giltiga och faktiskt om dessa surrogatpar kan representera det kodade tecknet, öppna en webbläsare DevTool och ange console.log('\uD83D\uDE0A');
I konsolen.
Du kan också använda detta onlineverktyg för att generera UTF-16-Kodpunkter.
Unicode – Teckenplan
ett plan är en kontinuerlig grupp med 21 eller 65 536 Kodpunkter. Eftersom UTF-16 har begränsat Kodpunkter till högst 10ffff, har vi totalt 17 teckenplan i Unicode-standarden från 0 till 16.
eftersom 21-tecken kan definieras av den enda kodenheten i UTF-16 (inklusive surrogatkodpunkter) bildar den det första (0: e) planet. Detta plan innehåller nästan alla tecken på grundläggande språk runt om i världen. Det är därför detta plan kallas Basic Multilingual Plane eller BMP.
därefter har vi Kodpunkter definierade av två kodenheter av UTF-16. Dessa innehåller 22⁰-tecken eftersom vi har 20 bitar för att koda kodpunktvärdet. Dessa är indelade i 16 plan (2si x 21 mm). Dessa kallas kompletterande plan.
För mer information om dessa plan, Läs detta Wikipedia-dokument.
jämförelse med UCS-2
UCS-2 är en 16-bitars kodning med fast bredd. Det betyder att endast en 16-bitars kodenhet används för att representera en kodpunkt. I teorin kan UCS-2 representera 21 Al distinkta tecken men det finns en vridning.
bisexuell btw, vi använder termen kodenhet i denna kodning med fast bredd för att förstå förhållandet mellan UTF-16. I verkligheten finns det inget sådant som kodenhet i någon fast med kodning.
eftersom UCS följer Unicode-teckenuppsättningen är kodningen av tecknen i UCS-2 identisk med kodningen av tecknen i UTF-16 som representeras i bara en kodenhet.
Brasilien eftersom UCS följer Unicode-teckenuppsättningen kan den inte koda ett giltigt tecken med kodpunkterna reserverade för surrogaten.
så i nötskal innehåller UCS-2 tecknen i grundläggande flerspråkigt plan. Detta är anledningen, vissa äldre dokument och programvara som används UCS-2 kodning. Men UCS-2-kodning har blivit föråldrad och UTF-16 föredras.
Endianness och BOM
som vi diskuterade tidigare innehåller en UTF-kodade dokument på låg nivå sekvensen av kodenheter. För UTF-8 är kodenheten 8 bitar lång medan för UTF-16 är den 16 bitar lång. Dessa kodenheter utgör tecknen.
en UTF-8-eller UTF-16-avkodare läser kodenheterna sekventiellt, en kodenhet i taget för att generera tecknen.
varje kodenhet representerar ett numeriskt värde som en UTF-8-eller UTF-16-avkodare kan ta en titt på och bestämma om det är tillräckligt att representera ett tecken eller om det följer andra kodenheter som också bör övervägas.
När det gäller UTF-8 är det enkelt. Eftersom varje kodenhet är 8 bitar lång är det snabbt och enkelt att konvertera det 8-bitars binära talet till ett numeriskt värde. Detta är dock inte fallet med UTF-16.
UTF-16 kodenhet är ett 16-bitars (2 byte) binärt tal som representerar ett kodpunktvärde. Att generera det numeriska värdet från flera byte är i allmänhet knepigt och olika system beter sig annorlunda.
detta beteende beror på systemets endianness. Från vår tidigare diskussion om endianness finns det två sätt att skriva ett UTF-16-kodenhetsvärde. Antingen i Big-endian-format eller Little-Endian-format.
i Big-endian-format lagras MSB först och LSB lagras sist. Hittills skriver vi UTF-16-kodenhetsvärdet i Big-endian-formatet. För att skriva UTF-16-kodenhetsvärde i Little-endian måste vi byta byte.
låt oss prata om karaktären av den. Från det tidigare exemplet kan det representeras i bara en kodenhet av UTF-16 och dess kodning i hexadecimal representation ser ut som 0906^,.
0906 är ett 16-bitars tal där 09 är MSB och 06 är LSB. Därför i Big-endian arkitektur, det kommer att lagras som 09 06. Men i en Little-endian-arkitektur kommer den att lagras som 06 09.därför blir det vårt ansvar att koda tecken genom att ta endianness av systemet i åtanke så att systemet kan läsa ett UTF-16-dokument korrekt.
men hur kan vi berätta i förväg om en användares maskin är kompatibel med det kodade dokumentet eller inte? Och eftersom endianness av ett system kan påverka hur ett dokument avkodas, hur delar vi det offentligt?
det är här BOM kommer in i bilden. A Byte Order Mark (BOM) är en byte sekvens som läggs till i början av en textfil eller textdata.
Unicode rekommenderar tecken med kodpunkt FEFFOVICENT att fungera som en BOM för UTF-16 och UTF-32 kodningar. Denna karaktär bör före dokumentets första tecken. Detta tecken kommer dock inte att beaktas av avkodaren i utgången.
detta tecken (U + FEFF) är ett nollbredd icke-brytande mellanslag (ZWNBSP) tecken och det är osynligt. Därför, även om en avkodare inte känner igen BOM, kommer den inte att producera någon synlig utgång.
detta tecken representeras i en enda kodenhet av UTF-16 och i hexadecimal representation ser det ut som FE (MSB) och FF (LSB).
därför när tecken kodas i Big-endian-format måste vi lägga till FEFF som BOM i början av filen och när tecken kodas i Little-endian-format måste vi lägga till FFFE (omvänd) som BOM i början av filen.
Unicode rekommenderar att du lägger till BOM i UTF-16-kodat dokument. Men om BOM saknas antas Big-endian-formatet.
IANA föredrar UTF-16 som identifierare för att beteckna ett UTF-16-kodat dokument. UTF-16be används dock för dokument kodade i Big-endian-format och UTF-16LE används för Little-endian-format.
När UTF-16be eller UTF-16LE namn används, rekommenderas inte BOM att läggas till i en fil. Även i det här fallet, om BOM läggs till, kommer det att betraktas som ZWNBSP-tecken och det kommer inte att ignoreras.
namn på UTF-16, UTF-16be och UTF-16LE är skiftlägeskänsliga.
fördelar och nackdelar
UTF-16 är effektiv eftersom den bara har 2 kodenheter och eftersom de flesta använda tecken faller i BMP-uppsättningen kan de representeras i bara en kodenhet. Det kommer dock med många problem.
den största nackdelen med UTF-16 är att den inte är ASCII-kompatibel. Eftersom ASCII-tecken kodas med en enda kodenhet (16-bitars nummer) kan de inte avkodas ordentligt av en ASCII-avkodare.
UTF-16 förbrukar onödigt utrymme för ASCII-tecken. Jämfört med det UTF-8-kodade dokumentet som bara innehåller ASCII-tecken är storleken på samma dokument som kodats i UTF-16 två gånger större.
UTF – 16 påverkas också av systemets endianness. Om BOM saknas och en lämplig kodningsidentifierare inte används (som UTF-16LE) kanske ett UTF-16-kodat dokument inte avkodas korrekt.
på grund av karaktären av UTF-16-kodning har den infört surrogatkodpunkter som inte kan representera de giltiga tecknen. Det har också begränsat Unicode-teckenuppsättningen till 10ffffundvit (sista kodpunkten).
trots dessa fakta, några av programmeringsspråken som JavaScript, Java, etc. och system som Windows föredrar UTF-16-kodning.