调用Shell时编码错误


9

我正在尝试DOT图,并尝试执行以下操作:

:! dot -Tpng -oFab.png %

我收到一个错误,因为我的文件名有一个特殊字符(ó“Fabricación”中的“”):

C:\windows\system32\cmd.exe /c ( dot -Tpng -oFab.png Fabricaci├│n.gv)
Error: dot: can't open Fabricaci├│n.gv
shell returned 2
Hit any key to close this window...

如您所见,特殊字符已更改为“ ├│”。这是Win7和NTFS下的vim和gVim 7.4,因此我假设文件名位于UTF16中。我还假设调用shell / cmd时,文件名被解释为其他某种编码(感谢Carpetsmoker指出它默认为代码页850)。

我怎样才能解决这个问题?

当然,我可以简单地重命名该文件,但是我想知道为什么会发生这种情况以及如何更正它。

更新:我刚刚在superuser.SE中发现了这个问题(感谢@ ChristianBrabandt的反馈),但似乎也无济于事。


1
我很好奇,如果在Cygwin或MobaXterm(适用于Windows的类似Unix的便携式环境)下的命令行上使用Vim会遇到相同的错误。我怀疑不是。可能有一种方法可以实际解决此问题,以便Windows cmd接受文件名,但是我喜欢安装类似Unix的环境。
通配符

2
根据我的阅读,默认值cmd.exe不是unicode,而是代码页850另请参阅此答案
马丁·图尔诺伊

谢谢@Carpetsmoker。我随意使用您提供的信息来更新我的问题。
罗夫洛

我不确定,但您可能需要调整“ termencoding”选项。
克里斯蒂安·布拉班德

@ChristianBrabandt除非我做错了,否则似乎没有帮助。我尝试将tenc设置为latin1,utf8和cp850。似乎没有人能做到。
罗夫洛

Answers:


2

简短答案

问题出在dot.exe。GraphViz可以在Linux中打开带有Unicode路径的文件,但不能在Windows中打开,除非(也许)是使用Visual Studio 2005编译的。

研究

代码页设置为850,Vim编码设置为UTF-8

在此处输入图片说明

它没有给出完全相同的错误,但是dot.exe似乎收到了错误的参数。我尝试将相同的文件名传递给其他程序。

在此处输入图片说明

而且效果很好。同时执行dot.exetype直接执行都可以cmd.exe得到相同的结果,因此Windows控制台和Vim都不是问题。可能导致该错误的下一件事就是dot.exe它自己。我怀疑它只是不知道如何正确处理Unicode编码的参数,因为甚至不是所有控制台命令都可以:

https://ss64.com/nt/chcp.html

如果需要完全的Unicode支持,请使用PowerShell。在CMD Shell中,对Unicode的支持仍然非常有限,管道,重定向和大多数命令仍然仅是ANSI。唯一有效的命令是DIR,FOR / F和TYPE,这允许读取和写入(UTF-16LE / BOM)文件和文件名,但没有其他内容。

我在网上搜索了GraphViz中是否支持Unicode,发现它确实支持Unicode 文件,但没有关于文件名的Unicode支持。我既未在GraphViz错误跟踪器上找到任何报告,也未在论坛上找到有关其他人有兴趣阅读Unicode命名文件的帖子。因此,我在源代码中进行了查找。这里是什么dot.exe入口点的样子:

graphviz-2.40.1\cmd\dot\dot.c

int main(int argc, char **argv)
{
    . . .

/* --------------------> ARGS ARE BEING PASSED HERE */
    gvParseArgs(Gvc, argc, argv);

    . . .

argv下来的兔子洞:graphviz-2.40.1\lib\common\args.c

int gvParseArgs(GVC_t *gvc, int argc, char** argv)
{
    int rv;
    if ((argc = neato_extra_args(gvc, argc, argv)) < 0)    return (1-argc);
    if ((argc = fdp_extra_args(gvc, argc, argv)) < 0)      return (1-argc);
    if ((argc = memtest_extra_args(gvc, argc, argv)) < 0)  return (1-argc);
    if ((argc = config_extra_args(gvc, argc, argv)) < 0)   return (1-argc);

/* -------------------->  HERE GO ALL NON-FLAG ARTUMENTS */
    if ((rv = dotneato_args_initialize(gvc, argc, argv)))  return rv;

    if (Verbose) gvplugin_write_status(gvc);
    return 0;
}

graphviz-2.40.1\lib\common\input.c

int dotneato_args_initialize(GVC_t * gvc, int argc, char **argv)
{
    for (i = 1; i < argc; i++) {
        if (argv[i] && argv[i][0] == '-') {

            . . .

/* -------------------->  JUST CASUALLY COPYING CHAR POINTERS */
        } else if (argv[i])
            gvc->input_filenames[nfiles++] = argv[i];
    }

最后 graphviz-2.40.1\lib\common\input.c

graph_t *gvNextInputGraph(GVC_t *gvc)
{
    . . . .

/* -------------------->  OPENING THE FILES FOR READ WITH FOPEN */
    while ((fn = gvc->input_filenames[fidx++]) && !(fp = fopen(fn, "r")))  {

        . . .

    }

如MDSN所述:

FOPEN函数打开由filename指定的文件。_wfopenfopen的宽字符版本;_wfopen的参数是宽字符字符串。否则_wfopenfopen的行为相同。简单地使用_wfopen对文件流中使用的编码字符集没有影响。

在Visual C ++ 2005中,fopen支持Unicode文件流。

可悲的是,唯一的选择是重命名文件。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.