2014-05-18 47 views
2

對於一個小項目,我需要在Windows的CMD中輸出可能已本地化的文本字符串,並且從程序的參數中讀取一些字符串。爲了簡化問題,我將使用一個簡單的回聲程序作爲演示。如何在命令行的語言環境中顯示文本?

請考慮在C語言片段:

#include <stdio.h> 

int main(int argc, char **argv) { 
    // Display the first argument through the standard output: 
    if (argc > 1) 
     puts(argv[1]); 
    return 0; 
} 

這是兩個執行的輸出:

$ test.exe Wilhelm 
$ Wilhelm 

$ test.exe Röntgen 
$ R÷ntgen 

在那裏,你已經可以看到的東西像ö這將是從ASCII的不會正確顯示。但是,他們在節目中正確識別,例如,如果你這樣做:

if (argv[1][1] == 'ö') 
    puts("It is."); 

的句子會被顯示出來,所以程序正確接收的字符。

所以我雖然,OK,那可能需要wchar_t的事情,所以做適當的修改和定義UNICODE_UNICODE你會得到:

#include <stdio.h> 

int wmain(int argc, wchar_t **argv) { 
    // Display the first argument through the standard output: 
    if (argc > 1) 
     _putws(argv[1]); 
    return 0; 
} 

不過這個測試程序的輸出將是相同的。

環顧四周,閱讀文檔,我發現有些解決方法,例如將語言環境設置爲英語:文本將正確顯示。修改的第一個版本(無wchar_t S)我結束了與此:

#include <stdio.h> 
#include <locale.h> 

int main(int argc, char **argv) { 
    // Get the previous locale and change to English: 
    char *old_locale = setlocale(LC_ALL, NULL); 
    setlocale(LC_ALL, "English"); 
    // Display the first argument through the standard output: 
    if (argc > 1) 
     puts(argv[1]); 
    // Restore locale: 
    setlocale(LC_ALL, old_locale); 
    return 0; 
} 

"en-US"似乎並不在MinGW的-W64工作,而"English"作品與它和Microsoft Visual C++)

現在程序可以打印,以便在命令行窗口中正確顯示字符。

問題在於,將事情設置爲英語並不是西班牙語系統或日語系統中最好的事情。所以我想以某種方式從系統中獲取語言環境。我發現了一個叫_get_current_locale函數返回一個_locale_t,但它似乎不是我想要的東西都:

_locale_t_variable->locinfo->lc_category[LC_ALL].locale(這是一個char *)似乎是NULL

所以問題是,如何獲取或顯示命令行的語言環境中的文本?在Windows'CMD中處理本地化文本的正確方法是什麼(不一定是Unicode)?

+0

你的問題有可取之處。 'echo'程序可以在我的Win7機器上正確回顯'Röntgen';所以你試圖做的顯然是可能的。 –

+0

但是,再次,'echo'是MS cmd shell的內部。它可以通過外殼進行'特殊'處理... –

+0

默認情況下,命令提示符使用OEM代碼頁。設置C語言環境是無關緊要的。但是,您可以更改此代碼頁。 –

回答

0

「這些是兩個輸出...」:如果您使用的是cmd.exe,爲什麼提示符類似於美元符號?你是這樣設定的嗎?如果你發現它的,這可以解釋你意想不到的觀察

mode con cp /status 

:如果你真的是使用CMD.EXE,你可以勾選「代碼頁上的」。打開charmap。exe,你會發現你關心的角色被稱爲「帶有Diaresis的U + 00F6拉丁小寫字母O」。如果您在使用代碼頁437粘貼到CLI對此,一些有趣的事情發生......

將傳遞到Unicode程序將是代碼:0xF6爲0x00你的程序將獲得此代碼。

該字符被識別爲代碼頁437中存在,但代碼爲0x94。我相信CLI(包括echo命令)會執行一些所見即所得,而後面的代碼(0x94)會顯示給您並輸出到標準輸出

如果將字符從CLI複製到剪貼板,它將獲得與「OEM文本」和0x94代碼的附加關聯。

現在讓我們切換到代碼頁:

mode con cp select=1252 

此代碼頁中,當您從字符映射表粘貼到CLI,通過爲Unicode程序代碼保持相同之前的場景。

但是現在你看到的字符是0xF6在終端字體,讓您有分工號(這在視覺上類似於代碼頁437的字體)。 echo命令將發送相同的代碼到stdout

如果將字符從CLI複製到剪貼板,它將獲得與「OEM文本」和0x94代碼的其他關聯,與以前相同。

如果重定向的輸出回波命令與該字符的文件,並使用終端字體在記事本打開一個文件,你會看到師跡象。如果您將字體更改爲Courier New,則會根據Unicode顯示「帶過濾功能的小o」。

現在切換回代碼頁:

mode con cp select=437 

如果你想在Windows的Unicode程序的輸出翻譯的Unicode序列的FILE *,我認爲你必須使用二進制模式。要修改原來的代碼,你可能有:

#define _UNICODE 

#include <locale.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include <tchar.h> 
#include <fcntl.h> 
#include <io.h> 

int __cdecl _tmain(int argc, TCHAR ** argv, TCHAR ** envp) { 
    wchar_t bom = 0xFEFF; 

    _setmode(_fileno(stdout), _O_BINARY); 

    _ftprintf(stdout, _T("%c"), bom); 
    _putts(argv[1]); 

    return EXIT_SUCCESS; 
    } 

在這個例子中,我們在寫UTF-16字符前寫UTF-16LE字節順序標記( 「BOM」)參數爲stdout。這將看在CLI醜陋的,但如果你重定向到文件或直接與文件工作(二進制模式),其結果可能是沿着你最初在感興趣的線路更多:

#define _UNICODE 

#ifdef _UNICODE 
#define BOM { 0xFF, 0xFE, 0, 0 } 
#else 
#define BOM { 0 } 
#endif 

#include <locale.h> 
#include <stdio.h> 
#include <stdlib.h> 

#include <tchar.h> 
#include <fcntl.h> 
#include <io.h> 

int __cdecl _tmain(int argc, TCHAR ** argv, TCHAR ** envp) { 
    /* Initialize the BOM string */ 
    static const union { 
     unsigned char bytes[sizeof (TCHAR) * 2]; 
     TCHAR c[2]; 
     } bom = BOM; 
    FILE * f; 
    TCHAR filename[] = _T("testfile.txt"); 
    int r; 
    int rc; 

    /* Assume failure */ 
    rc = EXIT_FAILURE; 

    if (argc != 2) { 
     _ftprintf(stderr, _T("Usage: %s <word>\n"), argv[0]); 
     goto err_usage; 
     } 

    f = _tfopen(filename, _T("wb")); 
    if (!f) { 
     _ftprintf(stderr, _T("Could not open file: %s\n"), filename); 
     goto err_fopen; 
     } 

    r = _ftprintf(f, _T("%s"), bom.c); 
    if (r != _tcsclen(bom.c)) { 
     _ftprintf(stderr, _T("Could not write BOM to file\n")); 
     goto err_bom; 
     } 

    r = _ftprintf(f, _T("%s"), argv[1]); 
    if (r != _tcsclen(argv[1])) { 
     _ftprintf(stderr, _T("Could not write argument to file\n")); 
     goto err_arg; 
     } 

    rc = EXIT_SUCCESS; 

    err_arg: 

    err_bom: 

    fclose(f); 
    err_fopen: 

    err_usage: 

    return rc; 
    } 

這裏有一些額外的資源,這可能會幫助:

_tfopenhttp://msdn.microsoft.com/en-us/library/yeby3zcb.aspx

_ftprintfhttp://msdn.microsoft.com/en-us/library/xkh07fe2.aspx

_setmodehttp://msdn.microsoft.com/en-us/library/tw4k6df8.aspx

的關於Unicode文本和二進制流:http://msdn.microsoft.com/en-us/library/c4cy2b8e.aspx

SBCS,MBCS,Unicode函數:http://msdn.microsoft.com/en-us/library/tsbaswba.aspx

相關問題