Inleiding tot tekenset

UTF-16

UTF-16 is een 16-bit variabele lengte coderingsschema en het gebruikt de UTF tekenset voor tekencodepunten. Dit betekent dat een UTF-16 gecodeerd teken een 16-bit code eenheid zal hebben.

omdat we weten dat een UTF-8 gecodeerd teken kan worden weergegeven in 1 tot 4 code-eenheden, kan een UTF-16-teken worden weergegeven in 1 of 2 code-eenheden. Vandaar kan een UTF-16 karakter 16 of 32 beetjes geheugen nemen die op zijn codepunt worden gebaseerd.

voordat u in de UTF-16-coderingsspecificaties springt, laten we begrijpen hoe we UTF-16 kunnen laten werken.

omdat we 16-bits code-eenheid hebben, kunnen we in theorie 21⁶-tekens coderen van codepunt 0 tot 65.535. Maar wat als we een karakter hebben met het codepunt groter dan 65.535? In dat geval kunnen we een andere code-eenheid toevoegen.

met de extra code-eenheid kunnen we in totaal 232 tekens coderen, wat meer is dan 4M. maar dan is de vraag hoe een UTF-16 decoder weet dat hij 2 code-eenheden moet overwegen om een teken te decoderen?

UTF-8 loste dit probleem op door initiële bits van de eerste code-eenheid en continuation code-eenheden in te stellen op een aantal specifieke bit-waarden die een UTF-8 decoder kan gebruiken om af te trekken hoeveel code-eenheden een karakter kan nemen.

we kunnen hetzelfde doen met de UTF-16 code eenheid, maar dan moeten we enkele bits in een code eenheid opgeven voor deze functie. We kunnen enkele initiële bits van een code-eenheid instellen op een betekenisvolle waarde die een UTF-16 decoder kan begrijpen.

ook om zelfsynchroniserend vermogen te geven aan codeeenheden, moet een codeeenheid kunnen vertellen of het de initiële codeeenheid of een vervolgcodeeenheid is en niet een teken van slechts één codeeenheid.

dus besloot Unicode om de initiële 6 bits van de code-eenheid op te offeren, waardoor er slechts 10 bits overblijven om het codepunt van een teken per code-eenheid te coderen. Als een teken 2 codeeenheden nodig heeft, bevat 20 bits van het geheugen (van 32 bits of 4 bytes) de werkelijke codepuntinformatie van het teken.

dus wat zijn deze initiële bits en hoe deze bits een deuk maken in de UTF-tekenset? Laten we het onderstaande voorbeeld volgen.

1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
FIRST CODE UNIT---- SECOND CODE UNIT---

vanaf de UTF-16-standaard moet de eerste code-eenheid beginnen met 110110₂ en de tweede code-eenheid moet beginnen met 110111₂. Dit zal een UTF-16 decoder helpen om te begrijpen welke als de eerste code eenheid en welke is de tweede. Dit maakt UTF-16 self-synchronizing.

nu wat we hebben 10 bits per code eenheid om mee te spelen, Wat is het bereik dat we kunnen spelen binnen? Uiteindelijk, hoeveel tekens kunnen worden gecodeerd in twee code-eenheden van UTF-16 codering?

maak je geen zorgen, we zullen het hebben over tekens die gecodeerd zijn in slechts één code-eenheid.

Als u de bovenstaande code-eenheidssjablonen bekijkt, hebben we een bereik van 1101 1000 0000 0000₂ tot 1101 1111 1111 1111₂. Dat is gelijk aan D800₁₆ aan dfff₁₆.

💡 de eerste codeeenheid heeft een bereik van D800₁₆ tot 6fff₁₆ en de tweede codeeenheid heeft een bereik van dc00₁₆ tot DFFF₁₆. We kunnen deze waarden krijgen door alle Codepunten bits aan en uit te zetten.

aangezien UTF-16 zelfsynchroniserend moet zijn, mogen Codepunten tussen D800₁₆ en dfff₁₆ geen teken in UTF-16 vertegenwoordigen. Aangezien alle UTF-coderingen dezelfde UTF-tekenset volgen, worden deze Codepunten beperkt door UTF en worden ze niet en zullen ze niet worden toegewezen aan tekens⁰.

Codepunten tussen D800₁₆ en dfff₁₆ vertegenwoordigen geen tekens, vandaar dat ze surrogaatcodepunten worden genoemd of samen worden ze ook wel surrogaatparen⁰ genoemd.

het eerste surrogaatcodepunt (van de eerste codeeenheid) ook wel hoog surrogaatpunt genoemd en het tweede codepunt (van de tweede codeeenheid) ook wel laag surrogaatpunt genoemd. Dat maakt het totaal van 2048 Codepunten, 1024 per draagmoeder.

💁 ♂ surrogaatcodepunten offerden hun leven op zodat we meer tekens konden coderen met twee codeeenheden. Denk daar eens over na!

dus de grote vraag, kunnen we een teken coderen met een enkele code eenheid van UTF-16? Het antwoord is ja. UTF-16 is een 16-bit variabele lengte codering schema. Dus betekent dat, we kunnen coderen 21 characters tekens met een enkele code eenheid?

het antwoord is nee. In theorie, kunnen we coderen 21⁶ tekens met code punt 0000₁₆ (0₁₀) te FFFF₁₆ (65535₁₀), maar de code-punten tussen D800₁₆ en DFFF₁₆ vertegenwoordigen niet alle karakters zoals ze zijn voorbehouden.

daarom is het veilig om tekens te coderen van 0000₁₆ tot d7ff₁₆ en E000₁₆ tot Ffff₁₆ waardoor er 63.488 (65536-2048) tekens overblijven. Dit is alleen voor de tekens die kunnen worden gecodeerd in slechts één code-eenheid van UTF-16.

omdat we in totaal 20 bits hebben om mee te spelen als het gaat om karakters dan gecodeerd kan worden in 2 code-eenheden van UTF-16, kunnen we 22⁰ meer karakters coderen, wat 1.048.576 karakters is.

dus in totaal kunnen we 1,048,576 + 63,488 coderen wat neerkomt op 1,112,064 tekens (meer dan 1miljoen tekens). Dit is de limiet van de UTF-tekenset. Omdat UTF-16 Deze vele karakters kan coderen, kunnen andere UTF-coderingen geen karakters voorstellen die verder gaan dan deze.

UTF charset Codepunten

omdat we weten dat een codepunt een decimale waarde is die aan een teken is toegewezen, mogen we (Unicode) geen ongeldig codepunt toewijzen aan een feitelijk teken. Tot nu toe zijn de ongeldige Codepunten surrogaat Codepunten.

met slechts een enkele UTF-16 code-eenheid, kunnen we 63.488 tekens coderen, variërend van 0000₁₆ tot d7ff₁₆ en E000₁₆ tot Ffff₁₆. Het Laatste codepunt is 65.535. Deze worden BMP-tekens genoemd (later uitgelegd).

Met Twee code-eenheden van UTF-16 kunnen we 1.048.576 tekens coderen. Omdat we niet opnieuw kunnen beginnen met 0 waarde (codepunt) omdat deze na BMP tekens komen, moeten we ze compenseren met 65,536. Deze karakters worden aanvullende karakters genoemd (later uitgelegd).

daarom heeft het eerste aanvullende teken een codepuntwaarde van 65536₁₀, wat gelijk is aan 10000₁₆. Aangezien we 1,048,576 tekens kunnen coderen met twee code-eenheden van UTF-16, is het laatste codepunt 1114111₁₀ wat gelijk is aan 10ffff₁₆.

dus laten we de dingen opsplitsen in een eenvoudige tabelvorm.

+-----------+---------------------+--------------------+
| 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 |
+-----------+---------------------+--------------------+

Met deze kennis, laten we eens kijken hoe we sommige tekens in UTF-16 kunnen coderen. Laten we een eenvoudig ASCII-teken a (codepunt: 41₁₆), een teken uit Hindi (Indiase) taal आ (uitgesproken als AA, codepunt: 906₁₆) en een emoticon 😊 (genoemd als Happy Face, codepunt: 1f60a₁₆) kiezen.

zoals we uit de bovenstaande tabel kunnen zien, kunnen zowel A Als आ worden gecodeerd in slechts één code-eenheid van UTF-16 omdat hun waarden kleiner zijn dan FFFF₁₆.

wanneer we een teken in slechts één code-eenheid moeten coderen, hoeven we alleen het codepunt van het teken in een 16-bits binair getal te converteren. Voor de tekens A is 00000000 01000001₂ de UTF-16 representatie.

evenzo, voor het karakter आ, hoeven we alleen maar het codepunt 906₁₆ te converteren naar een 16-bits binair getal dat 00001001 00000110₂ is.

normaal gesproken vertegenwoordigen we code-eenheden van een teken in hexadecimale getallen. Daarom is voor teken a de UTF-16 representatie 0041₁₆ en op dezelfde manier is voor het teken UTF-16 representatie आ 0906₁₆.

voor het teken 😊 zijn de dingen een beetje anders. Het codepunt is 1F60A₁₆. Als we kijken naar de UTF-16 tabel hierboven, het moet worden gecodeerd in 2 code eenheden van UTF-16. Hoe beginnen we?

eerst moeten we 10000₁₆ aftrekken van het codepunt. De reden hiervoor is dat elk teken gecodeerd in 2 code-eenheden van UTF-16 na de BMP-tekens komt waarvan het laatste codepunt FFFF₁₆ is.

om de werkelijke waarde te krijgen van bits die gebruikt worden voor codering (dat is 20 in 2 codeeenheden), moeten we 10000₁₆ aftrekken van het codepunt en het uiteindelijke getal gebruiken om deze 20 bits te genereren.

💡 om u te helpen beter te begrijpen, zal het eerste teken vertegenwoordigd met 2 code-eenheden van UTF-16 al zijn 20 bits op 0 gezet hebben. Dus de waarde van de bits die gebruikt worden om het codepunt van dit teken te coderen is 0. Maar toch is het codepunt 10000₁₆ volgens Unicode-tekenset. Dit is omdat de waarde die door deze 20 beetjes wordt opgebracht aan 10000₁₆ wordt toegevoegd om het definitieve codepunt te genereren.

zoals eerder gezien, zien deze 2 code-eenheden er hieronder uit.

1101 10xx xxxx xxxx 1101 11xx xxxx xxxx
FIRST CODE UNIT---- SECOND CODE UNIT---

We hoeven alleen deze 20 bits (x) te vullen met de waarde die wordt ontvangen van het tekencodepunt. Het codepunt van het teken 😊is 1F60A₁₆. Maar eerst moeten we er 10000₁₆ van Aftrekken. We krijgen F60A₁₆.

nu moeten we f60a₁₆ converteren naar een 20-bits binair getal en de 20 bits in de bovenstaande code eenheid template vullen. F60A₁₆ in binair is 0000111101 1000001010₂. Nu kunnen we deze 20 plaatshouders vullen.

hieronder staan de uiteindelijke code-eenheden.

1101 1000 0011 1101 1101 1110 0000 1010
0xD83D 0xDE0A

de snelle manier om te controleren of deze code-eenheden geldig zijn en in feite of deze surrogaatparen het gecodeerde teken kunnen vertegenwoordigen, open een Browser DevTool en voer console.log('\uD83D\uDE0A'); in de console.

(Chrome Developer Tools)

u kunt deze online tool ook gebruiken om UTF-16 Codepunten te genereren.

Unicode-Tekenvlakken

een vlak is een continue groep van 21⁶ of 65.536 Codepunten. Aangezien UTF-16 Codepunten heeft beperkt tot een maximum van 10FFFF₁₆, hebben we in totaal 17 karakters vliegtuigen in Unicode standaard beginnend van 0 tot 16.

aangezien 21⁶-tekens kunnen worden gedefinieerd door de eenheid van één code van UTF-16 (inclusief surrogaatcodepunten), vormt het het eerste (0De) vlak. Dit vliegtuig bevat bijna alle personages in basistalen over de hele wereld. Dit is de reden waarom dit vliegtuig wordt genoemd de basis meertalige vliegtuig of BMP.

vervolgens hebben we Codepunten gedefinieerd door twee codeeenheden van UTF-16. Deze bevatten 22 characters tekens omdat we 20 bits hebben om de codepuntwaarde te coderen. Deze zijn verdeeld in 16 vlakken (2⁴ x 21⁶). Dit zijn zogenaamde aanvullende vliegtuigen.

💡 voor meer informatie over deze vlakken, lees dit Wikipedia-document.

vergelijking met UCS-2

UCS-2 is een 16-bit codering met vaste breedte. Dat betekent dat slechts één 16-bit code eenheid wordt gebruikt om een codepunt te vertegenwoordigen. In theorie kan UCS-2 21⁶ verschillende karakters vertegenwoordigen, maar er is een twist.

BT BTW, we gebruiken de term code-eenheid in deze codering met vaste breedte om de relatie tussen UTF-16 te begrijpen. In werkelijkheid is er niet zoiets als code-eenheid in een vaste met codering.

aangezien UCS de Unicode-tekenset volgt, is de codering van de tekens in UCS-2 identiek aan de codering van de tekens in UTF-16 die in slechts één code-eenheid worden weergegeven.

💡 omdat UCS de Unicode-tekenset volgt, kan het geen geldig teken coderen met de Codepunten gereserveerd voor de surrogaten.

dus in het kort bevat UCS-2 de karakters van het meertalige basisvlak. Dit is de reden, sommige oudere documenten, en software gebruikt UCS-2 codering. Maar UCS-2-codering is verouderd en UTF-16 heeft de voorkeur.

Endianness en BOM

zoals we eerder hebben besproken, bevatten UTF-gecodeerde documenten op een laag niveau de reeks code-eenheden. Voor UTF-8 is de codeeenheid 8 bits lang, terwijl voor UTF-16 16 bits lang is. Deze code-eenheden vormen de tekens.

een UTF – 8 of UTF-16 decoder leest de code-eenheden achtereenvolgens, één code-eenheid per keer om de tekens te genereren.

elke code-eenheid vertegenwoordigt een numerieke waarde die een UTF-8-of UTF-16-decoder kan bekijken en beslissen of het voldoende is om een teken weer te geven of dat het andere code-eenheden volgt die ook in aanmerking moeten worden genomen.

als het gaat om UTF-8, zijn de dingen eenvoudig. Aangezien elke codeeenheid 8 bits lang is, is het omzetten van dat 8-bits binaire getal naar een numerieke waarde snel en eenvoudig. Dit is echter niet het geval met UTF-16.

UTF-16 code eenheid is een 16-bit (2 bytes) binair getal dat een code punt waarde vertegenwoordigt. Het genereren van de numerieke waarde uit meerdere bytes is over het algemeen lastig en verschillende systemen gedragen zich anders.

Dit gedrag hangt af van de endianness van het systeem. Uit onze eerdere discussie over endianness, zijn er twee manieren waarop we een UTF-16 code eenheidswaarde kunnen schrijven. Ofwel in Groot-endiaans formaat of klein-endiaans formaat.

in Big-endian formaat wordt de MSB als eerste opgeslagen en de LSB als laatste. Tot nu toe schrijven we de UTF-16 code eenheidswaarde in het Big-endian formaat. Om de waarde van de eenheid UTF-16 code in Little-endian te schrijven, moeten we bytes omwisselen.

laten we het hebben over karakter आ. Uit het eerdere voorbeeld, kan het worden weergegeven in slechts één code eenheid van UTF-16 en de codering in hexadecimale vertegenwoordiging ziet eruit als 0906₁₆.

0906₁₆ is een 16-bits getal met 09 als MSB en 06 als LSB. Vandaar dat in de Big-endian architectuur, het zal worden opgeslagen als 09 06. Echter, in Een Little-endian architectuur, het zal worden opgeslagen als 06 09.

daarom is het onze verantwoordelijkheid om tekens te coderen door rekening te houden met endianness van het systeem, zodat het systeem een UTF-16 document correct kan lezen.

maar hoe kunnen we van tevoren zien of de machine van een gebruiker compatibel is met het gecodeerde document of niet? En aangezien de endianess van een systeem invloed kan hebben op hoe een document wordt gedecodeerd, hoe delen we het dan Openbaar?

Dit is waar BOM in beeld komt. Een bytevolgorde Mark (BOM) is een bytevolgorde die aan het begin van een tekstbestand of tekstgegevens wordt toegevoegd.

Unicode raadt teken met codepunt FEFF₁₆ aan om te fungeren als een bom voor UTF-16 en UTF-32 coderingen. Dit teken zou vóór het eerste teken van het document moeten staan. Echter, dit karakter zal niet worden beschouwd door de decoder in de uitvoer.

Dit teken (u + FEFF) is een ZWNBSP-teken (zero-width non-breaking space) en het is onzichtbaar. Dus zelfs als een decoder de BOM niet herkent, zal het geen zichtbare uitvoer produceren.

dit karakter wordt weergegeven in een enkele code-eenheid van UTF-16 en in hexadecimale representatie lijkt het op FE (MSB) en FF (LSB).

dus als karakters in Big-endian formaat gecodeerd zijn, moeten we FEFF toevoegen als de BOM aan het begin van het bestand en als karakters in Little-endian formaat gecodeerd zijn, moeten we FFFE (reverse) toevoegen als de BOM aan het begin van het bestand.

Unicode raadt aan de BOM toe te voegen aan UTF-16 gecodeerd document. Echter, als de BOM ontbreekt dan wordt Big-endian formaat aangenomen.

IANA geeft de voorkeur aan UTF-16 als de identifier om een UTF-16 gecodeerd document aan te duiden. UTF-16BE wordt echter gebruikt voor document gecodeerd in Big-endian formaat en UTF-16LE wordt gebruikt voor Little-endian formaat.

wanneer UTF-16BE of UTF-16LE naam wordt gebruikt, dan wordt BOM niet aanbevolen om te worden toegevoegd aan een bestand. Zelfs in dit geval, als de BOM wordt toegevoegd, dan zal het worden beschouwd als ZWNBSP karakter en het zal niet worden genegeerd.

💡 UTF-16, UTF-16BE en UTF-16LE namen zijn hoofdletterongevoelig.

voors en tegens

UTF-16 is efficiënt omdat het slechts 2 code-eenheden heeft en omdat de meeste gebruikte tekens in de BMP-set vallen, kunnen ze in slechts één code-eenheid worden weergegeven. Echter, het komt met veel problemen.

het grootste nadeel van UTF-16 is dat het niet compatibel is met ASCII. Aangezien ASCII-tekens worden gecodeerd met een enkele code-eenheid (16-bit-nummer), kunnen ze niet correct worden gedecodeerd door een ASCII-decoder.

UTF-16 verbruikt onnodige ruimte voor ASCII-tekens. Vergeleken met het UTF-8-gecodeerde document dat alleen ASCII-tekens bevat, is de grootte van hetzelfde document dat in UTF-16 is gecodeerd twee keer groter.

UTF-16 wordt ook beïnvloed door de endianness van het systeem. Als de BOM ontbreekt en er geen geschikte coderingsidentifier wordt gebruikt (zoals UTF-16LE), wordt een UTF-16 gecodeerd document mogelijk niet goed gedecodeerd.

vanwege de aard van UTF-16-codering, heeft het surrogaatcodepunten geïntroduceerd die niet de geldige tekens kunnen vertegenwoordigen. Ook heeft het de Unicode-tekenset beperkt tot 10FFFF₁₆ (laatste codepunt).

ondanks deze feiten, sommige van de programmeertalen zoals JavaScript, Java, enz. en systemen zoals Windows geven de voorkeur aan UTF-16 codering.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.