Основной причиной этого вопроса является моя попытка написать тесты для нового модуля обработки параметров/аргументов ( OptArgs) для Перл. Это, конечно, включает разбор @ARGV
, который я делаю на основе ответов на этотвопрос. Это прекрасно работает в системах, где определен I18N::Langinfo::CODESET[1].
В системах, где langinfo(CODESET)
недоступен, я хотел бы, по крайней мере, сделать все возможное, основываясь на наблюдаемом поведении. Однако мои тесты до сих пор показывают, что в некоторых системах я даже не могу правильно передать юникод-аргумент внешнему скрипту.
Мне удалось запустить что-то вроде следующего в различных системах, где «test_script» — это Perl-скрипт, который просто выполняет print Dumper(@ARGV)
:
use utf8;
my $utf8 = '¥';
my $result = qx/$^X test_script $utf8/;
Я обнаружил, что на FreeBSD test_script получает байты, которые можно декодировать во внутренний формат Perl. Однако в OpenBSD и Solaris test_script получает строку "\x{fffd}\x{fffd}"
, которая содержит только символ замены Unicode (дважды?).
Я не знаю механизма, лежащего в основе оператора qx
. Я предполагаю, что это либо exec
, либо оболочка, но в отличие от файловых дескрипторов (где я могу binmode их для кодирования) я не знаю, как убедиться, что он делает то, что я хочу.То же самое с system()
. Итак, мой вопрос в том, что я не делаю правильно выше? В противном случае, чем отличается Perl, оболочка или среда в OpenBSD и Solaris?
[1] На самом деле я пока думаю, что это только Linux по результатам тестеров CPAN.
Обновление(x2):В настоящее время я прохожу через настройки 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();
Я опубликую результаты на различных системах, когда они поступят. Любые комментарии относительно действительности и или правильности этого будут оценены. Обратите внимание, что он непредназначен для проверки. Целью вышеизложенного является возможность сравнить то, что получено в разных системах.
Резолюция : Реальная основная проблема оказывается чем-то, что не рассматривается ни в моем вопросе, ни в ответе Шверна ниже. Я обнаружил, что на некоторых машинах cpantesters установлена/доступна только локаль ascii. Я не должен ожидать, что любая попытка передать символы UTF-8 программам в среде такого типа сработает. Итак, в конце концов моя проблема заключалась в неверных условиях тестирования, а не в неверном коде.
До сих пор я не видел ничего, что указывало бы на то, что оператор qx
или модуль utf8::all
каким-либо образом влияют на то, как параметры передаются внешним программам. Критически важным компонентом являются переменные окружения LANG
и/или LC_ALL
, чтобы сообщить внешней программе, в какой локали они работают.
Между прочим, мое первоначальное утверждение, что мой код работал на всех системах, где I18N::Langinfo::CODESET определен неправильно.