windows - utf8 - chcp 1252
¿Qué codificación/página de códigos está usando cmd.exe? (5)
El comando CHCP muestra la página de códigos actual. Tiene tres dígitos: 8xx y es diferente de Windows 12xx. Por lo tanto, al escribir un texto solo en inglés, no vería ninguna diferencia, pero una página de códigos extendida (como el cirílico) se imprimirá de forma incorrecta.
Cuando abro cmd.exe en Windows, ¿qué codificación está usando?
¿Cómo puedo verificar qué codificación está usando actualmente? ¿Depende de mi configuración regional o hay alguna variable de entorno para verificar?
¿Qué sucede cuando escribes un archivo con una cierta codificación? A veces me aparecen caracteres confusos (se utiliza una codificación incorrecta) y otras veces funciona. Sin embargo, no confío en nada mientras no sepa lo que está pasando. ¿Alguien puede explicar?
He estado frustrado por mucho tiempo por los problemas de la página de códigos de Windows, y los problemas de localización y portabilidad de los programas en C que causan. Las publicaciones anteriores han detallado los temas en detalle, por lo que no voy a agregar nada al respecto.
Para resumir la historia, finalmente terminé escribiendo mi propia capa de biblioteca de compatibilidad UTF-8 sobre la biblioteca C estándar de Visual C ++. Básicamente, esta biblioteca garantiza que un programa de C estándar funciona correctamente, en cualquier página de códigos, utilizando UTF-8 internamente.
Esta biblioteca, llamada MsvcLibX, está disponible como código abierto en https://github.com/JFLarvoire/SysToolsLib . Principales características:
- Las fuentes de C están codificadas en UTF-8, utilizando cadenas de caracteres [] C normales y las API de biblioteca de C estándar.
- En cualquier página de códigos, todo se procesa internamente como UTF-8 en su código, incluida la rutina main () argv [], con entrada y salida estándar convertidas automáticamente a la página de códigos correcta.
- Todas las funciones de archivo stdio.h son compatibles con las rutas de acceso UTF-8> 260 caracteres, hasta 64 KBytes en realidad.
- Las mismas fuentes pueden compilarse y enlazarse con éxito en Windows usando Visual C ++ y MsvcLibX y Visual C ++ C library, y en Linux usando gcc y Linux standard C library, sin necesidad de bloques #ifdef ... #endif.
- Los agregados incluyen archivos comunes en Linux, pero faltan en Visual C ++. Ej: unistd.h
- Agrega funciones faltantes, como las de E / S de directorios, administración de enlaces simbólicos, etc., todas con soporte de UTF-8, por supuesto :-).
Más detalles en el archivo README de MsvcLibX en GitHub , incluido cómo construir la biblioteca y usarla en sus propios programas.
La sección de lanzamiento en el repositorio GitHub anterior proporciona varios programas que utilizan esta biblioteca MsvcLibX, que mostrará sus capacidades. Ejemplo: pruebe mi herramienta which.exe con directorios con nombres que no sean ASCII en la RUTA, busque programas con nombres que no sean ASCII y cambie las páginas de códigos.
Otra herramienta útil es el programa conv.exe. Este programa puede convertir fácilmente un flujo de datos desde cualquier página de códigos a cualquier otra. Su valor predeterminado es la entrada en la página de códigos de Windows y la salida en la página de códigos de la consola actual. Esto permite ver correctamente los datos generados por las aplicaciones de la GUI de Windows (por ejemplo, el Bloc de notas) en una consola de comandos, con un comando simple como: type WINFILE.txt | conv
type WINFILE.txt | conv
Esta biblioteca de MsvcLibX no es de ninguna manera completa, ¡y las contribuciones para mejorarla son bienvenidas!
Para responder a su segunda consulta re. Cómo funciona la codificación, Joel Spolsky escribió un gran artículo introductorio sobre esto . Muy recomendado.
Tipo
chcp
para ver tu página de códigos actual (como ya dijo Dewfy).
Utilizar
nlsinfo
para ver todas las páginas de códigos instaladas y averiguar qué significa su número de página de códigos.
nlsinfo
tener instalado el kit de recursos de Windows Server 2003 (funciona en Windows XP) para usar nlsinfo
.
Sí, es frustrante: a veces los type
y otros programas imprimen imprecisiones y otras veces no.
En primer lugar, los caracteres Unicode solo se mostrarán si la fuente de la consola actual contiene los caracteres . Entonces, use una fuente TrueType como la consola Lucida en lugar de la fuente raster predeterminada.
Pero si la fuente de la consola no contiene el carácter que está intentando mostrar, verá signos de interrogación en lugar de incoherencias. Cuando se hace galimatías, hay más cosas que solo ajustes de fuente.
Cuando los programas utilizan las funciones estándar de E / S de la biblioteca C, como printf
, la codificación de salida del programa debe coincidir con la codificación de salida de la consola , o de lo contrario obtendrás un alboroto. chcp
muestra y establece la página de códigos actual. Todas las salidas que utilizan las funciones estándar de E / S de la biblioteca C se tratan como si estuvieran en la página de códigos mostrada por chcp
.
Hacer coincidir la codificación de salida del programa con la codificación de salida de la consola se puede lograr de dos maneras diferentes:
Un programa puede obtener la página de códigos actual de la consola usando
chcp
oGetConsoleOutputCP
, y configurarse para generar esa codificación, oUsted o un programa pueden configurar la página de códigos actual de la consola usando
chcp
oSetConsoleOutputCP
para que coincida con la codificación de salida predeterminada del programa.
Sin embargo, los programas que utilizan las API de Win32 pueden escribir cadenas UTF-16LE directamente en la consola con WriteConsoleW
. Esta es la única forma de obtener una salida correcta sin configurar páginas de códigos. E incluso al usar esa función, si para empezar no hay una cadena en la codificación UTF-16LE, un programa Win32 debe pasar la página de códigos correcta a MultiByteToWideChar
. Además, WriteConsoleW
no funcionará si la salida del programa se redirige; se necesita más violín en ese caso.
type
funciona algunas veces porque comprueba el inicio de cada archivo para una marca de orden de bytes (BOM) UTF-16LE, es decir, los bytes 0xFF 0xFE
. Si encuentra tal marca, muestra los caracteres Unicode en el archivo usando WriteConsoleW
independientemente de la página de códigos actual. Pero al type
cualquier archivo sin una lista de materiales UTF-16LE, o para utilizar caracteres que no sean ASCII con cualquier comando que no llame a WriteConsoleW
deberá configurar la página de códigos de la consola y la codificación de salida del programa para que coincidan entre sí.
¿Cómo podemos descubrir esto?
Aquí hay un archivo de prueba que contiene caracteres Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Aquí hay un programa Java para imprimir el archivo de prueba en un montón de diferentes codificaciones Unicode. Podría estar en cualquier lenguaje de programación; solo imprime caracteres ASCII o bytes codificados en la stdout
.
import java.io.*;
public class Foo {
private static final String BOM = "/ufeff";
private static final String TEST_STRING
= "ASCII abcde xyz/n"
+ "German äöü ÄÖÜ ß/n"
+ "Polish ąęźżńł/n"
+ "Russian абвгдеж эюя/n"
+ "CJK 你好/n";
public static void main(String[] args)
throws Exception
{
String[] encodings = new String[] {
"UTF-8", "UTF-16LE", "UTF-16BE", "UTF-32LE", "UTF-32BE" };
for (String encoding: encodings) {
System.out.println("== " + encoding);
for (boolean writeBom: new Boolean[] {false, true}) {
System.out.println(writeBom ? "= bom" : "= no bom");
String output = (writeBom ? BOM : "") + TEST_STRING;
byte[] bytes = output.getBytes(encoding);
System.out.write(bytes);
FileOutputStream out = new FileOutputStream("uc-test-"
+ encoding + (writeBom ? "-bom.txt" : "-nobom.txt"));
out.write(bytes);
out.close();
}
}
}
}
¿La salida en la página de códigos por defecto? Basura total!
Z:/andrew/projects/sx/1259084>chcp
Active code page: 850
Z:/andrew/projects/sx/1259084>java Foo
== UTF-8
= no bom
ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
= bom
´╗┐ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
== UTF-16LE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
= bom
■A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
== UTF-16BE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
= bom
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
== UTF-32LE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺ ↓☺ z☺ |☺ D☺ B☺
R u s s i a n 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N
♦ O♦
C J K `O }Y
= bom
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺ ↓☺ z☺ |☺ D☺ B☺
R u s s i a n 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N
♦ O♦
C J K `O }Y
== UTF-32BE
= no bom
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
= bom
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
Sin embargo, ¿qué pasa si type
los archivos que se guardaron? Contienen exactamente los mismos bytes que se imprimieron en la consola.
Z:/andrew/projects/sx/1259084>type *.txt
uc-test-UTF-16BE-bom.txt
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
uc-test-UTF-16BE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣☺↓☺z☺|☺D☺B
R u s s i a n ♦0♦1♦2♦3♦4♦5♦6 ♦M♦N♦O
C J K O`Y}
uc-test-UTF-16LE-bom.txt
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
uc-test-UTF-16LE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
uc-test-UTF-32BE-bom.txt
■ A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
uc-test-UTF-32BE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ☺♣ ☺↓ ☺z ☺| ☺D ☺B
R u s s i a n ♦0 ♦1 ♦2 ♦3 ♦4 ♦5 ♦6 ♦M ♦N
♦O
C J K O` Y}
uc-test-UTF-32LE-bom.txt
A S C I I a b c d e x y z
G e r m a n ä ö ü Ä Ö Ü ß
P o l i s h ą ę ź ż ń ł
R u s s i a n а б в г д е ж э ю я
C J K 你 好
uc-test-UTF-32LE-nobom.txt
A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺ ↓☺ z☺ |☺ D☺ B☺
R u s s i a n 0♦ 1♦ 2♦ 3♦ 4♦ 5♦ 6♦ M♦ N
♦ O♦
C J K `O }Y
uc-test-UTF-8-bom.txt
´╗┐ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
uc-test-UTF-8-nobom.txt
ASCII abcde xyz
German ├ñ├Â├╝ ├ä├û├£ ├ƒ
Polish ąęźżńł
Russian ð░ð▒ð▓ð│ð┤ðÁð ÐìÐÄÐÅ
CJK õ¢áÕÑ¢
Lo único que funciona es el archivo UTF-16LE, con una lista de materiales, impreso en la consola a través del type
.
Si usamos algo diferente al type
para imprimir el archivo, obtenemos basura:
Z:/andrew/projects/sx/1259084>copy uc-test-UTF-16LE-bom.txt CON
■A S C I I a b c d e x y z
G e r m a n õ ÷ ³ ─ Í ▄ ▀
P o l i s h ♣☺↓☺z☺|☺D☺B☺
R u s s i a n 0♦1♦2♦3♦4♦5♦6♦ M♦N♦O♦
C J K `O}Y
1 file(s) copied.
Del hecho de que la copy CON
no muestra Unicode correctamente, podemos concluir que el comando type
tiene lógica para detectar una lista de materiales UTF-16LE al inicio del archivo, y usar API especiales de Windows para imprimirlo.
Podemos ver esto abriendo cmd.exe
en un depurador cuando va a type
un archivo:
Después de que el type
abre un archivo, busca una lista de materiales de 0xFEFF
—es decir, los bytes 0xFF 0xFE
en little- 0xFF 0xFE
y si existe tal lista de materiales, el type
establece un fOutputUnicode
interno fOutputUnicode
. Este indicador se comprueba más tarde para decidir si llamar a WriteConsoleW
.
Pero esa es la única manera de obtener el type
para generar Unicode, y solo para archivos que tienen listas de materiales y están en UTF-16LE. Para todos los demás archivos, y para los programas que no tienen un código especial para manejar la salida de la consola, sus archivos se interpretarán de acuerdo con la página de códigos actual y probablemente se mostrarán como incomprensibles.
Puede emular la forma en que el type
genera Unicode en la consola en sus propios programas, así:
#include <stdio.h>
#define UNICODE
#include <windows.h>
static LPCSTR lpcsTest =
"ASCII abcde xyz/n"
"German äöü ÄÖÜ ß/n"
"Polish ąęźżńł/n"
"Russian абвгдеж эюя/n"
"CJK 你好/n";
int main() {
int n;
wchar_t buf[1024];
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
n = MultiByteToWideChar(CP_UTF8, 0,
lpcsTest, strlen(lpcsTest),
buf, sizeof(buf));
WriteConsole(hConsole, buf, n, &n, NULL);
return 0;
}
Este programa funciona para imprimir Unicode en la consola de Windows usando la página de códigos predeterminada.
Para el programa Java de muestra, podemos obtener un poco de salida correcta configurando la página de códigos manualmente, aunque la salida se confunde de formas extrañas:
Z:/andrew/projects/sx/1259084>chcp 65001
Active code page: 65001
Z:/andrew/projects/sx/1259084>java Foo
== UTF-8
= no bom
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
ж эюя
CJK 你好
你好
好
�
= bom
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
еж эюя
CJK 你好
你好
好
�
== UTF-16LE
= no bom
A S C I I a b c d e x y z
…
Sin embargo, un programa en C que establece una página de códigos UTF-8 de Unicode:
#include <stdio.h>
#include <windows.h>
int main() {
int c, n;
UINT oldCodePage;
char buf[1024];
oldCodePage = GetConsoleOutputCP();
if (!SetConsoleOutputCP(65001)) {
printf("error/n");
}
freopen("uc-test-UTF-8-nobom.txt", "rb", stdin);
n = fread(buf, sizeof(buf[0]), sizeof(buf), stdin);
fwrite(buf, sizeof(buf[0]), n, stdout);
SetConsoleOutputCP(oldCodePage);
return 0;
}
tiene salida correcta:
Z:/andrew/projects/sx/1259084>./test
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
La moraleja de la historia?
-
type
puede imprimir archivos UTF-16LE con una lista de materiales, independientemente de su página de códigos actual - Los programas de Win32 se pueden programar para enviar Unicode a la consola, utilizando
WriteConsoleW
. - Otros programas que configuran la página de códigos y ajustan la codificación de salida en consecuencia pueden imprimir Unicode en la consola, independientemente de cuál era la página de códigos cuando se inició el programa.
- Para todo lo demás, tendrás que perder el tiempo con
chcp
, y probablemente aún obtendrás resultados extraños.