Ruby system()不接受UTF-8?

时间:2012-08-01 22:16:01

标签: ruby unicode utf-8

我在Windows中使用Ruby 1.9.3并尝试执行一个操作,我将文件名写入每行一个文件(我们称之为文件列表),然后读取此文件列表,并调用system()运行另一个程序,我将从文件列表中传递一个文件名。我用system()调用的程序将采用我传递的文件名并将其转换为二进制格式,以便在专有系统中使用。

一切都可以达到调用system()的程度。我有一个UTF-8文件列表,从文件列表中读取文件名给了我正确的结果。但是当我跑步时

system("c:\foo.exe -arg #{bar}")

传递的arg“bar”不是UTF-8格式。如果我用日语,中文或任何文件名手动运行该程序它可以正常工作并正确编码文件,但如果我使用system()它,它不会。我知道bar中的变量是正确存储的,因为我在其他地方使用它没有问题。

我也试过了:

system("c:\foo.exe -arg #{bar.encoding("UTF-8")}")
system("c:\foo.exe -arg #{bar.force_encoding("UTF-8")}")

并且都不起作用。我只能假设这里的问题是将unicode传递给系统。

其他人是否可以确认系统是否支持或不支持此功能?

以下是代码块:

  $fname.each do |file|
    flist.write("#{file}\n")  # This is written properly in UTF-8
    system("ia.exe -r \"#{file}\" -q xbfadd") # The file being passed here is not encoding right!
  end

3 个答案:

答案 0 :(得分:3)

Ruby的system()函数与大多数脚本语言中的函数一样,是C标准库system()调用的贴面。 MS C运行时对所有面向字节的C stdlib函数使用Win32 ANSI API。

ANSI API使用Windows系统区域设置(也称为“ANSI代码页”)在面向字节的字符串和Windows的native-UTF16LE字符串之间进行映射,这些字符串用于文件名和shell命令。不幸的是,不可能将系统区域设置为UTF-8;您可以在特定控制台上将代码页设置为65001(Windows相当于UTF-8),但MS CRT在处理代码页65001时存在长期存在的错误,导致许多应用程序失败。

因此,使用标准的跨平台面向字节的C接口意味着您不能支持Unicode文件名或shell命令,这是相当悲伤的。一些脚本语言通过显式调用Win32'W'(Unicode)API而不是C stdlib接口添加了对Unicode文件名的支持。 Ruby 1.9.x正在这个领域取得进展,但system()还没有被关注过。

您可以calling the Win32 API yourself修复它,例如CreateProcessW,但它并不是特别漂亮。

答案 1 :(得分:0)

我赞成了鲍勃森的回答;我认为这是正确的。

我唯一要补充的是,额外的解决方法是将Windows命令行写入批处理文件,然后使用system()来调用批处理文件。

我使用这种方法成功解决了问题,同时为其标题中包含UTF-8 /非英语字符的书籍运行Calibre的电子书转换命令行工具。

答案 2 :(得分:0)

我认为鲍勃的回答是正确的。对我有用的解决方案是:

system("c:\foo.exe -arg #{bar.encoding("ISO-8859-1")}")