Ya, itu membuat frustrasi — kadang-kadang type
dan program lain mencetak omong kosong, dan terkadang tidak.
Pertama-tama, karakter Unicode hanya akan ditampilkan jika font konsol saat ini berisi karakter . Jadi gunakan font TrueType seperti Lucida Console daripada Raster Font default.
Tetapi jika font konsol tidak mengandung karakter yang Anda coba tampilkan, Anda akan melihat tanda tanya alih-alih omong kosong. Ketika Anda mendapatkan omong kosong, ada lebih banyak hal yang terjadi dari sekedar pengaturan font.
Ketika program menggunakan fungsi C-library I / O standar suka printf
, pengkodean keluaran program harus cocok dengan pengkodean keluaran konsol , atau Anda akan mendapatkan omong kosong. chcp
menunjukkan dan mengatur codepage saat ini. Semua output menggunakan fungsi I-O C-library standar diperlakukan seolah-olah itu dalam codepage yang ditampilkan oleh chcp
.
Mencocokkan pengkodean keluaran program dengan pengkodean keluaran konsol dapat dilakukan dengan dua cara berbeda:
Suatu program bisa mendapatkan codepage saat ini konsol menggunakan chcp
atau
GetConsoleOutputCP
, dan mengkonfigurasi sendiri untuk output dalam pengkodean itu, atau
Anda atau program dapat mengatur codepage saat ini konsol menggunakan chcp
atau
SetConsoleOutputCP
untuk mencocokkan pengkodean keluaran default dari program.
Namun, program yang menggunakan Win32 API dapat menulis string UTF-16LE langsung ke konsol
WriteConsoleW
. Ini adalah satu-satunya cara untuk mendapatkan hasil yang benar tanpa mengatur halaman kode. Dan bahkan ketika menggunakan fungsi itu, jika sebuah string tidak ada dalam pengkodean UTF-16LE untuk memulai, program Win32 harus meneruskan codepage yang benar
MultiByteToWideChar
. Juga, WriteConsoleW
tidak akan berfungsi jika output program diarahkan; lebih banyak mengutak-atik dalam hal itu.
type
bekerja beberapa waktu karena memeriksa awal setiap file untuk Tanda Pesanan Byte (BOM) UTF-16LE , yaitu byte 0xFF 0xFE
. Jika menemukan tanda seperti itu, itu akan menampilkan karakter Unicode dalam file menggunakan WriteConsoleW
terlepas dari codepage saat ini. Tetapi ketika type
memasukkan file apa pun tanpa BOM UTF-16LE, atau untuk menggunakan karakter non-ASCII dengan perintah apa pun yang tidak memanggil WriteConsoleW
— Anda perlu mengatur codepage konsol dan output program untuk mencocokkan satu sama lain.
Bagaimana kita bisa mengetahui ini?
Berikut file uji yang mengandung karakter Unicode:
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Berikut adalah program Java untuk mencetak file uji dalam sekelompok pengkodean Unicode yang berbeda. Itu bisa dalam bahasa pemrograman apa pun; hanya mencetak karakter ASCII atau byte yang dikodekan ke 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();
}
}
}
}
Output dalam codepage default? Total sampah!
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}
Namun, bagaimana jika kita type
file yang disimpan? Mereka berisi byte yang sama persis yang dicetak ke konsol.
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 õ¢áÕÑ¢
Satu- satunya yang berfungsi adalah file UTF-16LE, dengan BOM, dicetak ke konsol via type
.
Jika kami menggunakan apa pun selain type
untuk mencetak file, kami mendapat sampah:
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.
Dari fakta yang copy CON
tidak menampilkan Unicode dengan benar, kita dapat menyimpulkan bahwa type
perintah memiliki logika untuk mendeteksi BOM UTF-16LE pada awal file, dan menggunakan Windows API khusus untuk mencetaknya.
Kita bisa melihat ini dengan membuka cmd.exe
debugger ketika type
keluar file:
Setelah type
membuka file, ia memeriksa BOM dari 0xFEFF
—ya, byte
0xFF 0xFE
dalam little-endian — dan jika ada BOM seperti itu, type
tetapkan fOutputUnicode
flag internal . Bendera ini diperiksa kemudian untuk memutuskan apakah akan menelepon WriteConsoleW
.
Tapi itu satu-satunya cara untuk mendapatkan type
keluaran Unicode, dan hanya untuk file yang memiliki BOM dan berada di UTF-16LE. Untuk semua file lain, dan untuk program yang tidak memiliki kode khusus untuk menangani output konsol, file Anda akan ditafsirkan sesuai dengan codepage saat ini, dan kemungkinan akan muncul sebagai omong kosong.
Anda dapat meniru bagaimana type
keluaran Unicode ke konsol di program Anda sendiri seperti:
#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;
}
Program ini berfungsi untuk mencetak Unicode pada konsol Windows menggunakan codepage default.
Untuk contoh program Java, kita bisa mendapatkan sedikit output yang benar dengan mengatur codepage secara manual, meskipun outputnya kacau dengan cara yang aneh:
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
…
Namun, program C yang menetapkan halaman kode 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;
}
memang memiliki output yang benar:
Z:\andrew\projects\sx\1259084>.\test
ASCII abcde xyz
German äöü ÄÖÜ ß
Polish ąęźżńł
Russian абвгдеж эюя
CJK 你好
Moral dari cerita ini?
type
dapat mencetak file UTF-16LE dengan BOM terlepas dari codepage Anda saat ini
- Program Win32 dapat diprogram untuk menampilkan Unicode ke konsol, menggunakan
WriteConsoleW
.
- Program lain yang mengatur codepage dan menyesuaikan pengkodean outputnya sesuai dapat mencetak Unicode pada konsol terlepas dari apa codepage itu ketika program dimulai
- Untuk semua hal lain, Anda harus dipusingkan
chcp
, dan mungkin masih akan mendapatkan output yang aneh.
WriteFile
melaporkan jumlah karakter yang ditulis alih-alih jumlah byte, jadi penulis buffered mencoba kembali byte 'tersisa' beberapa kali sebanding dengan jumlah karakter non-ASCII . Juga di 65001, membaca karakter non-ASCII gagal di conhost.exe karena mengasumsikan 1 byte ANSI per kode UTF-16 saat memanggilWideCharToMultiByte
.GetStdHandle(STD_OUTPUT_HANDLE)
dan Cstdout
adalah pegangan konsol. Dalam praktiknya, untuk menguji konsol, periksa apakahGetConsoleMode
berhasil. Juga, jangan gunakan_isatty
fungsi runtime C untuk memeriksa apakah deskriptor file I / O rendah adalah konsol; yang hanya memeriksa perangkat mode karakter, yang termasukNUL
di antaranya. Sebaliknya, panggil_get_osfhandle
dan periksa gagang secara langsung.Tipe
untuk melihat halaman kode Anda saat ini (seperti yang sudah dikatakan Dewfy).
Menggunakan
untuk melihat semua halaman kode yang diinstal dan mencari tahu apa artinya nomor halaman kode Anda.
Anda harus menginstal kit sumber daya Windows Server 2003 (berfungsi pada Windows XP) untuk menggunakan
nlsinfo
.sumber
nlsinfo
sepertinya tidak ada di Windows 7. 7.nlsinfo
juga tidak ada di mesin Windows XP SP3 saya.nlsinfo
juga tidak ada pada mesin Windows 10E.Untuk menjawab pertanyaan kedua Anda, ulang. bagaimana encoding bekerja, Joel Spolsky menulis artikel pengantar yang bagus tentang ini . Sangat direkomendasikan.
sumber
Command CHCP menunjukkan codepage saat ini. Ini memiliki tiga digit: 8xx dan berbeda dari Windows 12xx. Jadi, mengetik teks yang hanya berbahasa Inggris, Anda tidak akan melihat perbedaan, tetapi codepage yang diperluas (seperti Cyrillic) akan dicetak secara salah.
sumber
Saya sudah lama frustrasi dengan masalah halaman kode Windows, dan portabilitas program C dan masalah lokalisasi yang disebabkannya. Posting sebelumnya telah merinci masalah ini secara panjang lebar, jadi saya tidak akan menambahkan apa pun dalam hal ini.
Untuk membuat cerita panjang pendek, akhirnya saya akhirnya menulis layer library kompatibilitas UTF-8 saya sendiri di atas Visual C ++ standar C library. Pada dasarnya perpustakaan ini memastikan bahwa program C standar berfungsi dengan baik, di halaman kode apa pun, menggunakan UTF-8 secara internal.
Perpustakaan ini, disebut MsvcLibX, tersedia sebagai sumber terbuka di https://github.com/JFLarvoire/SysToolsLib . Fitur utama:
Lebih detail di README MsvcLibX di GitHub , termasuk cara membangun perpustakaan dan menggunakannya dalam program Anda sendiri.
Bagian rilis di repositori GitHub di atas menyediakan beberapa program menggunakan pustaka MsvcLibX ini, yang akan menunjukkan kemampuannya. Contoh: Coba alat which.exe saya dengan direktori dengan nama non-ASCII di PATH, mencari program dengan nama non-ASCII, dan mengubah halaman kode.
Alat lain yang bermanfaat adalah program conv.exe. Program ini dapat dengan mudah mengkonversi aliran data dari halaman kode mana saja ke halaman lainnya. Standarnya adalah input di halaman kode Windows, dan output di halaman kode konsol saat ini. Ini memungkinkan untuk melihat dengan benar data yang dihasilkan oleh aplikasi Windows GUI (mis: Notepad) di konsol perintah, dengan perintah sederhana seperti:
type WINFILE.txt | conv
Pustaka MsvcLibX ini sama sekali tidak lengkap, dan kontribusi untuk memperbaikinya dipersilahkan!
sumber
Di Jawa saya menggunakan pengkodean "IBM850" untuk menulis file. Itu memecahkan masalah.
sumber