Да, это расстраивает - иногда type
и другие программы печатают бред, а иногда нет.
Прежде всего, символы Unicode будут отображаться только в том случае, если текущий шрифт консоли содержит символы . Поэтому используйте шрифт TrueType, например Lucida Console, вместо стандартного шрифта Raster.
Но если консольный шрифт не содержит символа, который вы пытаетесь отобразить, вместо тарабарщины вы увидите вопросительные знаки. Когда вы получаете тарабарщину, происходит больше, чем просто настройки шрифта.
Когда программы используют стандартные функции ввода-вывода C-библиотеки, например printf
, выходная кодировка программы должна совпадать с выходной кодировкой консоли , иначе вы получите бред. chcp
показывает и устанавливает текущую кодовую страницу. Весь вывод, использующий стандартные функции ввода-вывода библиотеки C, обрабатывается так, как если бы он находился в отображаемой кодовой странице chcp
.
Сопоставление выходной кодировки программы с выходной кодировкой консоли можно выполнить двумя различными способами:
Программа может получить текущую кодовую страницу консоли, используя chcp
или
GetConsoleOutputCP
, и сконфигурировать себя для вывода в этой кодировке, или
Вы или программа можете установить текущую кодовую страницу консоли с помощью chcp
или
SetConsoleOutputCP
соответствовать выходной кодировке программы по умолчанию.
Однако программы, использующие Win32 API, могут записывать строки UTF-16LE непосредственно в консоль
WriteConsoleW
. Это единственный способ получить правильный вывод без установки кодовых страниц. И даже при использовании этой функции, если строка не находится в кодировке UTF-16LE для начала, программа Win32 должна передать правильную кодовую страницу
MultiByteToWideChar
. Также WriteConsoleW
не будет работать, если вывод программы перенаправлен; в этом случае нужно больше возиться.
type
работает некоторое время, потому что он проверяет начало каждого файла для метки порядка байтов UTF-16LE (BOM) , то есть байтов 0xFF 0xFE
. Если он находит такую метку, он отображает символы Unicode в файле, используя WriteConsoleW
независимо от текущей кодовой страницы. Но при использовании type
любого файла без спецификации UTF-16LE или при использовании символов, отличных от ASCII, с любой командой, которая не вызывает WriteConsoleW
, вам нужно будет настроить кодовую страницу консоли и кодировку вывода программы так, чтобы они соответствовали друг другу.
Как мы можем это выяснить?
Вот тестовый файл, содержащий символы Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Вот Java-программа для распечатки тестового файла в куче разных кодировок Unicode. Это может быть на любом языке программирования; он печатает только символы ASCII или закодированные байты в 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();
}
}
}
}
Выход в кодовой странице по умолчанию? Всего мусора!
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}
Тем не менее, что если мы type
сохраняем файлы? Они содержат те же байты, которые были напечатаны на консоли.
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 õ¢áÕÑ¢
Только вещь , которая работает в UTF-16LE файл с BOM, выводимого на консоль с помощьюtype
.
Если мы используем что-то кроме type
печати файла, мы получаем мусор:
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.
Из того факта, что copy CON
Unicode отображает некорректно, можно сделать вывод, чтоtype
команда имеет логику для определения спецификации UTF-16LE в начале файла и использования специальных API-интерфейсов Windows для ее печати.
Мы можем увидеть это, открыв cmd.exe
в отладчике, когда он выходит type
из файла:
После того, type
как файл открывается, он проверяет спецификацию - 0xFEFF
т.е. байты с прямым порядком байтов
0xFF 0xFE
- и, если такая спецификация существует, type
устанавливает внутренний fOutputUnicode
флаг. Этот флаг проверяется позже, чтобы решить, стоит ли звонить WriteConsoleW
.
Но это единственный способ получить type
Unicode и только для файлов, которые имеют спецификации и находятся в UTF-16LE. Для всех других файлов и для программ, которые не имеют специального кода для обработки вывода на консоль, ваши файлы будут интерпретироваться в соответствии с текущей кодовой страницей и, скорее всего, будут отображаться как бред.
Вы можете эмулировать, как type
выводит Unicode на консоль в ваших собственных программах следующим образом:
#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;
}
Эта программа работает для печати Unicode на консоли Windows с использованием кодовой страницы по умолчанию.
Для примера Java-программы мы можем получить немного правильного вывода, установив кодовую страницу вручную, хотя выходные данные путаются странным образом:
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
…
Однако, программа на C, которая устанавливает кодовую страницу Unicode UTF-8:
#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;
}
имеет правильный вывод:
Z:\andrew\projects\sx\1259084>.\test
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Мораль этой истории?
type
может печатать файлы UTF-16LE с спецификацией независимо от вашей текущей кодовой страницы
- Программы Win32 могут быть запрограммированы для вывода Unicode на консоль, используя
WriteConsoleW
.
- Другие программы, которые устанавливают кодовую страницу и соответственно корректируют свою выходную кодировку, могут печатать Unicode на консоли независимо от того, какой была кодовая страница при запуске программы.
- Со всем остальным вам придется возиться
chcp
, и, вероятно, вы получите странные результаты.
WriteFile
сообщается о количестве записанных символов вместо количества байтов, поэтому буферизованные записывающие устройства повторяют «оставшиеся» байты несколько раз пропорционально количеству не-ASCII символов. , Также в 65001 чтение не-ASCII-символов завершается неудачно в conhost.exe, поскольку при вызове он принимает 1 ANSI-байт на код UTF-16WideCharToMultiByte
.GetStdHandle(STD_OUTPUT_HANDLE)
и Cstdout
являются дескрипторами консоли. На практике, чтобы проверить консоль, проверьте, что этоGetConsoleMode
успешно. Кроме того, не используйте_isatty
функцию времени выполнения C, чтобы проверить, является ли дескриптор файла с низким I / O консолью; это просто проверяет устройство в символьном режиме, которое включает в себя,NUL
среди прочего. Вместо этого позвоните_get_osfhandle
и проверьте ручку напрямую.Тип
чтобы увидеть вашу текущую кодовую страницу (как уже сказал Dewfy).
использование
чтобы увидеть все установленные кодовые страницы и узнать, что означает номер вашей кодовой страницы.
Для использования необходимо установить комплект ресурсов Windows Server 2003 (работает на Windows XP)
nlsinfo
.источник
nlsinfo
что , кажется, не существует на моей Windows 7.nlsinfo
также не существует на моем компьютере с Windows XP SP3.nlsinfo
также не существует на компьютере с Windows 10E.Чтобы ответить на ваш второй запрос повторно. Как работает кодирование, Джоэл Спольски написал отличную вводную статью по этому вопросу . Настоятельно рекомендуется.
источник
Команда CHCP показывает текущую кодовую страницу. Он состоит из трех цифр: 8xx и отличается от Windows 12xx. Поэтому, печатая текст на английском языке, вы не увидите никакой разницы, но расширенная кодовая страница (например, кириллица) будет напечатана неправильно.
источник
Я долго расстраивался из-за проблем с кодовыми страницами Windows, а также из-за проблем переносимости и локализации программ на Си. В предыдущих постах подробно рассказывалось о проблемах, поэтому я не собираюсь ничего добавлять на этот счет.
Короче говоря, в конце концов я закончил писать свой собственный уровень библиотеки совместимости UTF-8 поверх стандартной библиотеки C Visual C ++. По сути, эта библиотека гарантирует, что стандартная программа на C работает правильно, в любой кодовой странице, используя UTF-8 внутри.
Эта библиотека, которая называется MsvcLibX, доступна в открытом доступе по адресу https://github.com/JFLarvoire/SysToolsLib . Основные характеристики:
Более подробная информация в MsvcLibX README на GitHub , в том числе о том, как собрать библиотеку и использовать ее в своих собственных программах.
Раздел выпуска в вышеупомянутом репозитории GitHub предоставляет несколько программ, использующих эту библиотеку MsvcLibX, которые покажут ее возможности. Пример: попробуйте мой инструмент which.exe с каталогами с не-ASCII-именами в PATH, поиск программ с не-ASCII-именами и изменение кодовых страниц.
Еще одним полезным инструментом является программа conv.exe. Эта программа может легко конвертировать поток данных из любой кодовой страницы в любую другую. По умолчанию он вводится в кодовой странице Windows и выводится в текущей кодовой странице консоли. Это позволяет правильно просматривать данные, сгенерированные приложениями Windows GUI (например, Notepad) в командной консоли, с помощью простой команды, такой как:
type WINFILE.txt | conv
Эта библиотека MsvcLibX ни в коем случае не является полной, и мы приветствуем вклад в ее улучшение!
источник
В Java я использовал кодировку «IBM850» для записи файла. Это решило проблему.
источник