2012-06-20 7 views
6

この質問の根本原因は、Perl用の新しいオプション/引数処理モジュール(OptArgs)のテストを書くことです。これはもちろん、私がthis質問への回答に基づいて行っている@ARGVの解析です。これはI18N :: Langinfo :: CODESETが定義されているシステムでうまく動作します[1]。Perlでユニコード引数を外部コマンドに渡すにはどうすればよいですか?

langinfo(CODESET)が利用できないシステムでは、少なくとも観察された動作に基づいて最善の努力をしたいと思います。しかし、私のテストでは、これまでのところ、一部のシステムでは、の外部スクリプトへのunicode引数を正しく渡すことができないことが示されています。

私は「test_scriptは」単にprint Dumper(@ARGV)をするPerlスクリプトである様々なシステム上で、次のようなものを実行するために管理している:

use utf8; 
my $utf8 = '¥'; 
my $result = qx/$^X test_script $utf8/; 

私は何を発見したことはFreeBSD上でtest_scriptがどのバイトを受信することですPerlの内部形式にデコードすることができます。しかし、OpenBSDとSolaris上でtest_scriptは、ユニコード置き換え文字(2回の?)だけを含む文字列"\x{fffd}\x{fffd}"を取得するように見えます。

私はqxオペレータの基礎となるメカニズムについてはわかりません。私はexecやシェルを外していると推測しますが、ファイルハンドルと違って(私はそれらをエンコードのためにbinmodeすることができます)、私はそれが私が望むことを確実にする方法を知らない。その点についてはsystem()と同じです。だから私の質問は私が上記のことを正しくしていないのですか?さもなければ、OpenBSDとSolarisのPerlやシェル、環境とは何が違うのですか?

[1]実際には私はこれまでのところCPANテスターの結果によるとLinuxだと思います。

アップデート(×2):私は現在、次はSchwernにの仮説をテストするcpantesterのセットアップを通して方法を実行しています

use strict; 
use warnings; 
use Data::Dumper; 

BEGIN { 
    if (@ARGV) { 
     require Test::More; 
     Test::More::diag("\npre utf8::all: " 
       . Dumper({ utf8 => $ARGV[0], bytes => $ARGV[1] })); 
    } 
} 

use utf8; 
use utf8::all; 

BEGIN { 
    if (@ARGV) { 
     Test::More::diag("\npost utf8::all: " 
       . Dumper({ utf8 => $ARGV[0], bytes => $ARGV[1] })); 
     exit; 
    } 
} 

use Encode; 
use Test::More; 

my $builder = Test::More->builder; 
binmode $builder->output,   ':encoding(UTF-8)'; 
binmode $builder->failure_output, ':encoding(UTF-8)'; 
binmode $builder->todo_output, ':encoding(UTF-8)'; 

my $utf8 = '¥'; 
my $bytes = encode_utf8($utf8); 

diag("\nPassing: " . Dumper({ utf8 => $utf8, bytes => $bytes, })); 

open(my $fh, '-|', $^X, $0, $utf8, $bytes) || die "open: $!"; 
my $result = join('', <$fh>); 
close $fh; 

ok(1); 
done_testing(); 

を、彼らが通ってくるとき、私は様々なシステム上で結果を投稿します。この妥当性や正しさについてのコメントは感謝の意を表します。有効なテストであることを意図しているのはではなく、であることに注意してください。上記の目的は、異なるシステムで受信されたものを比較できるようにすることです。

解決策:実際の根本的な問題は、私の質問やSchwernの答えで解決できないことが判明しました。私が発見したのは、cpantestersマシンの中にはasciiロケールだけがインストールされている/利用可能なものがあるということです。私はこのタイプの環境で動作するプログラムにUTF-8文字を渡す試みは期待できません。最終的に私の問題は無効なテスト条件であり、無効なコードではありませんでした。

qxオペレータまたはutf8::allモジュールが、パラメータが外部プログラムにどのように渡されるかに影響することは、これまで何も見ていません。重要なコンポーネントは、実行中のロケールを外部プログラムに知らせるために、LANGおよび/またはLC_ALLのように見えます。

ちなみに、私のコードはI18N :: Langinfo :: CODESETが定義されていますが間違っています。

+0

関連するノートでは、BSDは他の方法で壊れているようです。私はFreeBSDへのsshセッションを通じてユニコード文字を入力することさえできません。その結果、奇妙な端末動作が起こります。 –

+0

unicode-via-sshは、使用している端末と両方のシステムで 'TERM'が何をしているかによって大きく左右されます。 – sarnold

+0

OS Xで問題を再現することはできませんが、[utf8 :: all](https://metacpan.org/module/utf8::all)を試して、Unicodeを含むほとんどのUnicode機能を有効にしてみてください'@ ARGV'。 'qx'は、' utf8 :: all'がファイルハンドルをUnicodeにする 'open'プラグマの影響を受けるかもしれません。 – Schwern

答えて

1

qxはシェルに電話をかけると干渉する可能性があります。

これを回避するには、utf8::allを使用して、すべてのPerl Unicodeブードーを有効にします。次に、open関数を使用して、シェルを避けてプログラムへのパイプを開きます。

use utf8::all; 
my $utf8 = '¥'; 

open my $read_from_script, "-|", "test_script", $utf8; 
print <$read_from_script>,"\n"; 
+0

3引数バージョンのopenでシェルを使用するのは避けてください。しかし、私はutf8 :: allが 'open'関数や根本的な' exec'呼び出しの引数に与える影響を見ることはできません。 –

+0

utf8 :: allのソースを見ると、実際に[@ ARGV]のエンコーディングについての前提があります。(http://stackoverflow.com/questions/2037467/how-can-i-treat-command-line -arguments-as-utf-8-per-perl)は警告しています。しかし、それはこの質問から話題を外しています。 –

+0

@MarkLawrence 'utf8 :: all'は' open'プラグマを介して影響しています。具体的には 'use open":std "はおそらくSTDOUTにUTF-8を使用させることで、パイプのオープンを引き起こすようです。その良い例は、「他の誰かがそれを理解してモジュールを使う」という良い例です。そして、そうです、それは '@ ARGV'のエンコーディングについて仮定しています。たとえあなたがASCIIを想定していなくても、UTF-8がかなり安全な賭けであるとしても、あなたは仮定をしなければなりません。残念ながら、それは字句的に行うことはできません。 – Schwern

関連する問題