UTF-16 è a larghezza fissa o a larghezza variabile? Perché UTF-8 non ha problemi di ordine byte?


16
  1. UTF-16 è a larghezza fissa o a larghezza variabile? Ho ottenuto risultati diversi da diverse fonti:

    Da http://www.tbray.org/ongoing/When/200x/2003/04/26/UTF :

    UTF-16 memorizza i caratteri Unicode in blocchi di sedici bit.

    Da http://en.wikipedia.org/wiki/UTF-16/UCS-2 :

    UTF-16 (Unicode Transformation Format a 16 bit) è una codifica di caratteri per Unicode in grado di codificare 1.112.064 [1] numeri (chiamati punti di codice) nello spazio di codice Unicode da 0 a 0x10FFFF. Produce un risultato di lunghezza variabile di una o due unità di codice a 16 bit per punto di codice.

  2. Dalla prima fonte

    UTF-8 ha anche il vantaggio che l'unità di codifica è il byte, quindi non ci sono problemi di ordinamento dei byte.

    Perché UTF-8 non ha problemi di ordine byte? È a larghezza variabile e un carattere può contenere più di un byte, quindi penso che l'ordine dei byte possa ancora essere un problema?

Grazie e saluti!


Risposte:


13

(1) Cosa significa sequenza di byte, un arrary di char in C? UTF-16 è una sequenza di byte o che cos'è allora? (2) Perché una sequenza di byte non ha nulla a che fare con la lunghezza variabile?

Sembra che tu abbia frainteso quali siano le problematiche endian. Ecco un breve riassunto.

Un numero intero a 32 bit occupa 4 byte. Ora conosciamo l'ordinamento logico di questi byte. Se hai un numero intero a 32 bit, puoi ottenere il byte alto di questo con il seguente codice:

uint32_t value = 0x8100FF32;
uint8_t highByte = (uint8_t)((value >> 24) & 0xFF); //Now contains 0x81

Va tutto bene. Dove inizia il problema è come i vari hardware memorizzano e recuperano numeri interi dalla memoria.

In ordine Big Endian, un pezzo di memoria di 4 byte che leggi come numero intero a 32 bit verrà letto con il primo byte che è il byte alto:

[0][1][2][3]

Nell'ordine di Little Endian, un pezzo di memoria di 4 byte che leggi come numero intero a 32 bit verrà letto con il primo byte come byte basso :

[3][2][1][0]

Se si dispone di un puntatore a un puntatore a un valore a 32 bit, è possibile effettuare ciò:

uint32_t value = 0x8100FF32;
uint32_t *pValue = &value;
uint8_t *pHighByte = (uint8_t*)pValue;
uint8_t highByte = pHighByte[0]; //Now contains... ?

Secondo C / C ++, il risultato non è definito. Potrebbe essere 0x81. O potrebbe essere 0x32. Tecnicamente, potrebbe restituire qualsiasi cosa, ma per i sistemi reali, restituirà l'uno o l'altro.

Se si dispone di un puntatore a un indirizzo di memoria, è possibile leggere tale indirizzo come valore a 32 bit, valore a 16 bit o valore a 8 bit. Su una macchina big endian, il puntatore punta al byte alto; su una piccola macchina endian, il puntatore punta al byte basso.

Si noti che si tratta solo di leggere e scrivere nella / dalla memoria. Non ha nulla a che fare con il codice C / C ++ interno. La prima versione del codice, quella che C / C ++ non dichiara non definita, lo farà sempre per ottenere il byte alto.

Il problema è quando inizi a leggere i flussi di byte. Come da un file.

I valori a 16 bit presentano gli stessi problemi di quelli a 32 bit; hanno solo 2 byte anziché 4. Pertanto, un file può contenere valori a 16 bit memorizzati in ordine big endian o little endian.

UTF-16 è definito come una sequenza di valori a 16 bit . In effetti, è un uint16_t[]. Ogni singola unità di codice ha un valore di 16 bit. Pertanto, per caricare correttamente UTF-16, è necessario sapere qual è l'endianità dei dati.

UTF-8 è definito come una sequenza di valori a 8 bit . È un uint8_t[]. Ogni singola unità di codice ha una dimensione di 8 bit: un singolo byte.

Ora, sia UTF-16 che UTF-8 consentono a più unità di codice (valori di 16 bit o 8 bit) di combinarsi insieme per formare un punto di codice Unicode (un "carattere", ma non è il termine corretto; è una semplificazione ). L' ordine di queste unità di codice che formano un punto di codice è dettato dalle codifiche UTF-16 e UTF-8.

Durante l'elaborazione di UTF-16, leggi un valore a 16 bit, facendo qualunque conversione endian sia necessaria. Quindi, si rileva se si tratta di una coppia surrogata; se lo è, allora leggi un altro valore a 16 bit, combini i due e da quello ottieni il valore del punto di codice Unicode.

Durante l'elaborazione di UTF-8, leggi un valore di 8 bit. Non è possibile alcuna conversione endian, poiché esiste un solo byte. Se il primo byte indica una sequenza multibyte, allora leggi un certo numero di byte, come dettato dalla sequenza multibyte. Ogni singolo byte è un byte e quindi non ha una conversione endian. L' ordine di questi byte nella sequenza, proprio come l'ordine delle coppie surrogate in UTF-16, è definito da UTF-8.

Quindi non ci possono essere problemi di endian con UTF-8.


10

La risposta di Jeremy Banks è corretta, ma non ha affrontato l'ordinamento dei byte.

Quando si utilizza UTF-16, la maggior parte dei glifi viene archiviata utilizzando una parola a due byte, ma quando la parola viene archiviata in un file su disco, quale ordine viene utilizzato per memorizzare i byte costituenti?

Ad esempio, il glifo CJK (cinese) per la parola "acqua" ha una codifica UTF-16 in esadecimale di 6C34. Quando lo scrivi come due byte sul disco, lo scrivi come "big-endian" (i due byte sono 6C 34)? O lo scrivi come "little-endian (i due byte sono 34 6C)?

Con UTF-16, entrambi gli ordinamenti sono legittimi e di solito si indica quale dei file ha trasformando la prima parola nel file in un Byte Order Mark (BOM), che per la codifica big-endian è FE FF e per little-endian la codifica è FF FE.

UTF-32 presenta lo stesso problema e la stessa soluzione.

UTF-8 non ha questo problema, perché ha una lunghezza variabile e si scrive effettivamente una sequenza di byte di un glifo come se fosse un piccolo endian. Ad esempio, la lettera "P" viene sempre codificata utilizzando un byte - 80 - e il carattere sostitutivo viene sempre codificato utilizzando i due byte FF FD in quell'ordine.

Alcuni programmi mettono un indicatore a tre byte (EF BB BF) all'inizio di un file UTF-8, e questo aiuta a distinguere UTF-8 da codifiche simili come ASCII, ma non è molto comune se non su MS Windows.


Grazie! (1) la lettera "P" è solo un byte in UTF-8. Perché il carattere sostitutivo viene aggiunto al suo codice? (2) In UTF-8, ci sono altri caratteri che hanno più di un byte in UTF-8. Perché l'ordine dei byte tra byte per ciascuno di questi caratteri non è un problema?
StackExchange per tutto il

@Tim: (1) Non aggiungi il carattere sostitutivo al codice per P. Se vedi 80 FF FD, sono due caratteri: un carattere P e un carattere sostitutivo.
Bob Murphy,

(2) Scrivere e leggere sempre i due byte per il "carattere sostitutivo" come FF FD, in questo ordine. Ci sarebbe un problema di ordinamento dei byte solo se si potesse anche scrivere il "carattere sostitutivo" come FD FF - ma non è possibile; quella sequenza di due byte sarebbe qualcosa di diverso da un "carattere sostitutivo".
Bob Murphy,

1
@Tim: potresti voler lavorare su en.wikipedia.org/wiki/UTF-8 . È davvero abbastanza buono, e se riesci a capire tutto e le altre pagine Wikipedia relative a Unicode, penso che scoprirai che non hai più domande al riguardo.
Bob Murphy,

4
La ragione per cui UTF-8 non ha problemi con l'ordine dei byte è che la codifica è definita come una sequenza di byte e che non ci sono variazioni con endianness diverse. Non ha nulla a che fare con la lunghezza variabile.
Starblue,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.