在TCL中,默认是使用UTF-8编码的,所有输入的字符串最终都会转换为这一编码。这样就造成了一个问题,通常在不同系统下使用编辑器默认保存的编码是不同的,比如ns中提供的TCL文件都是采用UTF-8进行编码的,而简体中文Windows下默认的保存编码是GB2312(cp936)。
当我们在Windows平台下打开ns中的TCL文档时,首先后将它转换为GB2312,再进行修改,修改完成后如果没有特殊设置就保存为GB2312的文件。如果在此文件中只使用了英文一般不会有什么困扰,因为其在不同编码中保持不变。(!!!打倒英语特权!!!)如果直接在这些文件中使用中文或者其它的语言,就可能造成显示的乱码甚至于程序无法执行。
1、文件中的编码
对于文件中的编码,解决的方法有几种:
一种是修改完成后仍然将TCL文件保存为UTF8编码。不过这种方法转换的汉字有些字无法显示。
另一种是使用TCL中的encoding命令。当使用时出现乱码时,可以这样:
set string [encoding convertfrom cp936 “测试字符串”]
其中cp936必须和文件保存的编码一致,如果使用UTF-8编码,则相应改为utf-8。然后将出现字符串的地方用$string替换即可。
不过这种方法在vs2005下处理UTF-8文件时好像不能通过,原因不明。如果是保存为cp936就可以显示汉字。
这两种方法在实际使用过程中都有一些汉字无法显示,好像是在读取文件时调用了gets这个命令,而这个命令进行了错误的编码转换。当然,这两种方法是最简单的,如果你的汉字刚好可以显示,那么,恭喜了,一切都解决了。
如果这两种方法都不行,那么我们用最后一着:
set title [encoding convertfrom cp936 "/uCE/uC4/uBC/uFE"]
$m add command -label $title -command "puts {File}"
set title [encoding convertfrom cp936 "/uB0/uEF/uD6/uFA"]
$m add command -label $title -command "puts {Help}"
其中CE C4 BC FE就是"文件"两个字的CP936编码
B0 EF D6 FA是"帮助"两个字的CP936编码
这个编码通过UEDIT这样的十六进制编辑器就可以看到了(在文本模式下输入汉字,然后以16进制查看)。
或者自己写一小段C代码进行转换,就更容易了。
2、TCL与C混合编程时的编码问题
参看下面代码进行转换
int
_tmain(int argc, _TCHAR* argv[])
{
//
使用本语句即可使用所有编码
Tcl_FindExecutable(argv[0]);
Tcl_Interp *interp = Tcl_CreateInterp();
//
在C中设置TCL变量的值
string text = "
今天的天气传说是不错的好像"
;
Tcl_SetVar(interp, "text", text.c_str(), TCL_GLOBAL_ONLY);
Tcl_SetVar(interp, "ret", "", TCL_GLOBAL_ONLY);
//
对此字符串进行编码转换并进行其它处理
//
其中cp936就是C文件的编码
//
运算后的结果存放在$ret变量中
string code = "set text [encoding convertfrom cp936 $text] /n set ret [string range $text 1 5]";
Tcl_Eval(interp, code.c_str());
//
在C中取$ret变量的值
char *ret = 0;
ret = (char *)Tcl_GetVar(interp, "ret", TCL_GLOBAL_ONLY);
//
在TCL运算的中间都是使用UTF8编码的,最后的结果也是以与编码保存。
//
如果要在C代码中进行操作,则必须转换为Unicode或者ASCII。
//
此两行语句的次序不可颠倒,即必须首先转换为Unicode再转换为ASCII(根据需要)。
//
转换中使用的编码CP_UTF8与CP_ACP不可更改
wchar_t wchar[1024];
char ascii[1024];
int n = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, ret, strlen(ret), wchar, 1024);
n = ::WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, wchar, n, ascii, 1024, NULL, NULL);
ascii[n] = 0;
cout << "eval result: " << ascii << "(" << n << " byets)" << endl;
system("pause");
Tcl_DeleteInterp(interp);
}