4

私は Windows で Ruby 1.9.3 を使用しており、ファイル名を 1 行に 1 つずつファイルに書き込み (ファイルリストと呼びます)、後でこのファイルリストを読み取り、system() を呼び出して別のプログラムを実行するアクションを実行しようとしています。ここで、ファイルリストからファイル名を渡します。私が system() で呼び出しているそのプログラムは、私が渡したファイル名を受け取り、独自のシステムで使用されるバイナリ形式に変換します。

system() を呼び出す時点まで、すべてが機能します。UTF-8 ファイルリストがあり、ファイルリストからファイル名を読み取ると適切な結果が得られます。しかし、私が走るとき

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

渡される引数 "bar" が UTF-8 形式ではありません。日本語、中国語、またはその他のファイル名を使用してプログラムを手動で実行すると、正常に動作し、ファイルが正しくコーディングされますが、system() を使用して実行するとうまくいきません。問題なく他の場所で使用しているため、 bar の変数が適切に保存されていることはわかっています。

私も試しました:

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

どちらも機能しません。ここでの問題は、ユニコードをシステムに渡すことだけだと思います。

システムが実際にこれをサポートしているかどうかを他の誰かが確認できますか?

コードのブロックは次のとおりです。

  $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
4

3 に答える 3

3

Ruby のsystem()関数は、ほとんどのスクリプト言語と同様に、C 標準ライブラリsystem()呼び出しよりも飾り気のないものです。MS C ランタイムは、すべてのバイト指向の C stdlib 関数に Win32 ANSI API を使用します。

ANSI API は、Windows システム ロケール (別名「ANSI コードページ」) を使用して、バイト指向の文字列と、ファイル名やシェル コマンドに使用される Windows のネイティブ UTF16LE 文字列をマッピングします。残念ながら、システム ロケールを UTF-8 に設定することはできません。特定のコンソールでコードページを 65001 (Windows の UTF-8 に相当) に設定できますが、MS CRT にはコードページ 65001 の処理に長期にわたるバグがあり、多くのアプリケーションが失敗します。

したがって、標準のクロスプラットフォームのバイト指向の C インターフェイスを使用すると、Unicode ファイル名やシェル コマンドをサポートできなくなります。これはかなり悲しいことです。一部のスクリプト言語では、C stdlib インターフェイスの代わりに Win32 'W' (Unicode) API を明示的に呼び出すことにより、Unicode ファイル名のサポートが追加されています。Ruby 1.9.x はこの分野で進歩を遂げsystem()ていますが、まだ検討されていません。

CreateProcessWなどの Win32 API を自分で呼び出すことで修正できますが、特にきれいではありません。

于 2012-08-03T08:13:16.807 に答える
0

ボビンスの答えに賛成しました。私はそれが正しいと信じています。

私が追加したい唯一のことは、これはWindowsの問題である追加の回避策は、コマンドラインをバッチファイルに書き出してから、system()を使用してバッチファイルを呼び出すことです。

このアプローチを使用して、タイトルに UTF-8/英語以外の文字が含まれる本に対して Calibre の ebook-convert コマンドライン ツールを実行しているときに、問題をうまく回避しました。

于 2013-06-21T16:14:36.283 に答える