2014-05-18 48 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

相关问题