Pregunta

Descargo de responsabilidad: Mis disculpas por todo el texto a continuación (para una sola pregunta simple), pero creo sinceramente que cada información es relevante para la pregunta. Estaría feliz de aprender lo contrario. Solo puedo esperar que, si tiene éxito, las preguntas y las respuestas pueden ayudar a otros en una locura unicode. Aquí va.

He leído todos los sitios web generalmente considerados sobre UTF8, particularmente Éste es muy bueno para mis propósitos, pero también he leído los clásicos, como los mencionados en otras preguntas similares. Sin embargo, todavía me falta conocimiento sobre cómo integrarlo todo en mi laboratorio virtual. Yo uso emacs con

;; Internationalization
(prefer-coding-system 'utf-8)
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)

En mis .emacs, Xterm comenzó con

 LC_CTYPE=en_US.UTF-8 xterm -geometry 91x58\
-fn '-Misc-Fixed-Medium-R-SemiCondensed--13-120-75-75-C-60-ISO10646-1'

Y mi localidad dice:

LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

Mis preguntas son las siguientes (algunas de las respuestas pueden ser el comportamiento esperado de la aplicación, pero aún necesito darle sentido, así que tengan paciencia conmigo):

Suponiendo el siguiente programa C:

#include <stdio.h>

int main(void) {
  int c;
  while((c=getc(stdin))!=EOF) {
    if(c!='\n') {
      printf("Character: %c, Integer: %d\n", c, c);
    }
  }
  return 0;
}

Si ejecuto esto en mi Xterm, obtengo:

€
Character: � Integer: 226
Character: �, Integer: 130
Character: �, Integer: 172

(En caso de que los caracteres que obtengan sean un signo de interrogación blanco dentro de un círculo negro). Los INT son la representación decimal de los 3 bytes necesarios para codificar €, pero no estoy exactamente seguro de por qué Xterm no los muestra correctamente.

En cambio, Mousepad, por ejemplo, impresiones

Character: â, Integer: 226
Character: ,, Integer: 130 (a comma, standing forU+0082 <control>, why?!)
Character: ¬, Integer: 172

Mientras tanto, los emacs muestran

Character: \342, Integer: 226
Character: \202, Integer: 130
Character: \254, Integer: 172

PREGUNTA: La pregunta más general que puedo hacer es: ¿Cómo consigo que todo imprima el mismo personaje? Pero estoy seguro de que habrá seguimientos.

Gracias de nuevo y disculpas por todo el mensaje de texto.

¿Fue útil?

Solución

Ok, entonces su problema aquí se debe a la mezcla de llamadas de la biblioteca C de la vieja escuela (GetC, Printf %C) y UTF-8. Su código está leyendo correctamente los tres bytes que componen '€' - 226, 130 y 172 como decimales - pero estos valores individualmente no son glifos codificados UTF -8 válidos.

Si miras el Codificación UTF-8, Los valores enteros 0..127 son las codificaciones para el conjunto de caracteres original de US-ASCII. Sin embargo, 128..255 (es decir, todos sus bytes) son parte de un carácter Multibyte UTF-8, por lo que no corresponde a un carácter UTF-8 válido invidualmente.

En otras palabras, el byte único '226' no significa nada por sí solo (ya que es el prefijo de un carácter de 3 bytes, como se esperaba). los printf Llame Imprime como un solo byte, que no es válido con la codificación UTF-8, por lo que cada programa diferente hace frente al valor no válido de diferentes maneras.

Suponiendo que solo quiere 'ver' de qué está hecho el personaje de UTF -8 bytes, le sugiero que se adhiera a la salida entera que ya tiene (o tal vez use hexin Unicode No es probable que obtenga resultados consistentes en diferentes programas.

Otros consejos

La codificación UTF-8 dice que los tres bytes juntos en una cadena forman el signo del euro, o '€'. Pero los bytes individuales, como los producidos por su programa C, no tiene sentido en una transmisión UTF-8. Es por eso que son reemplazados por el "carácter de reemplazo" u+fffd, o '�'.

E-MACS es inteligente, sabe que los bytes únicos son datos no válidos para la secuencia de salida y lo reemplaza con una representación de escape visible del byte. La salida de mousepad está realmente rota, no puedo darle ningún sentido. Mousepad se está volviendo a caer a la códigos de códigos de Windows CP1252, donde los bytes individuales representan caracteres. La "coma" no es una coma, es una cita baja.

Lo primero que publicaste:

Character: � Integer: 226
Character: �, Integer: 130
Character: �, Integer: 172

Es la respuesta "correcta". Cuando imprime el carácter 226 y el terminal espera UTF8, no hay nada que el terminal pueda hacer, le dio datos no válidos. La secuencia "226" "espacio" es un error. Los ? El personaje es una buena manera de mostrarle que hay datos malformados en alguna parte.

Si desea replicar su segundo ejemplo, debe codificar correctamente el carácter.

Imagina dos funciones; Decode, que toma una codificación de personajes y una transmisión de octetos y produce una lista de caracteres; y codificar, que toma una codificación de una lista de caracteres y produce una secuencia de octetos. Code/Decode debe ser reversible cuando sus datos son válidos: code ('utf8', decode ('utf8', "...")) == "...".

De todos modos, en el segundo ejemplo, la aplicación ("Mousepad?") Está tratando cada octeto en la representación de tres octetos del carácter del euro como un carácter LATIN1 individual. Obtiene el octeto, lo decodifica de latín-1 a alguna representación interna de un "carácter" (no octeto o byte), y luego codifica ese carácter como UTF8 y lo escribe a la terminal. Por eso funciona.

Si tiene recodificación de GNU, intente esto:

$ recode latin1..utf8
<three-octet representation of the euro character> <control-D>
â¬

Lo que esto hizo fue tratar a cada octeto de la representación UTF-8 como un carácter Latin1, y luego convertir cada uno de esos caracteres en algo que su terminal puede entender. Quizás ejecutar esto a través de HD deja más claro:

$ cat | hd
€
00000000  e2 82 ac 0a               |....|
00000004

Como puede ver, son 3 octetos para la representación UTF-8 del personaje, y luego una nueva línea.

Ejecutando a través de Recode:

$ recode latin1..utf8 | hd
€
00000000  c3 a2 c2 82 c2 ac 0a      |.......|
00000007

Esta es la representación UTF-8 de la cadena de entrada "Latin1"; Algo que su terminal puede mostrar. La idea es que si sale a su terminal, verá el signo del euro. Si sale, no obtiene nada, eso no es válido. Finalmente, si sale, obtiene la "basura" que es la "representación UTF-8" del personaje.

Si esto parece confuso lo es. Nunca debe preocuparse por la representación interna como esta; Si está trabajando con caracteres y debe imprimirlos en un terminal UTF-8, siempre debe codificar a UTF-8. Si está leyendo un archivo codificado UTF-8, debe decodificar los octetos en caracteres antes de procesarlos en su aplicación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top