Как получить правильные аргументы командной строки не ASCII в ActiveState Perl?

Выполнение следующей команды

perl -e "for (my $i = 0; $i < length($ARGV[0]); $i++) {print ord(substr($ARGV[0], $i, 1)), qq{\n}; }" αβγδεζ

в Windows 7 cmd окно с ActiveState Perl v5.14.2 дает следующий результат:

97
223
63
100
101
63

Приведенные выше значения являются бессмысленными и не соответствуют какой-либо известной кодировке, поэтому пытаетесь декодировать их с помощью подхода, рекомендованного в разделе Как я могу рассматривать аргументы командной строки как UTF-8 в Perl? не помогает Изменение активной кодовой страницы командного окна не меняет результаты.

4 ответа

Решение

Ваша система, как и любая другая система Windows, которую я знаю, по умолчанию использует кодовую страницу 1252 ANSI, так что вы можете попробовать использовать

use Encode qw( decode );
@ARGV = map { decode('cp1252', $_) } @ARGV;

Обратите внимание, что cp1252 не может представлять все эти символы, поэтому консоль и, следовательно, Perl фактически получают

  • 97
  • 223
  • ? 63
  • д 100
  • е 101
  • ? 63

Существует "широкий" интерфейс для передачи (почти) любой точки кода Unicode в программу, но

  1. Широкий интерфейс не используется при вводе команды в командной строке.
  2. Perl использует интерфейс ANSI для извлечения параметров, поэтому даже если вы запустили Perl с использованием широкого интерфейса, параметры будут понижены до ANSI, когда Perl их получит.

Извините, но это ситуация типа "вы не можете". Вам нужен другой подход. Диомидис Спинеллис предлагает изменить кодовую страницу ANSI вашей системы следующим образом в Win7:

  1. Панель управления
  2. Регион и язык
  3. административный
  4. Язык для не-Unicode программ
  5. Установите Текущий язык для не-Unicode программ на язык, связанный с определенными символами (греческий в вашем случае).

На этом этапе вы будете использовать кодировку кодовой страницы ANSI, связанную с новой выбранной кодировкой, вместо cp1252 (cp1253 для греческого).

use Encode qw( decode );
@ARGV = map { decode('cp1253', $_) } @ARGV;

Обратите внимание, что с помощью chcp изменение кодовой страницы, используемой в окне консоли, не влияет на кодовую страницу, в которой Perl получает свои аргументы, которая всегда является кодовой страницей ANSI. См. Примеры ниже (cp737 - греческая кодовая страница OEM, а cp1253 - греческая кодовая страница ANSI. Вы можете найти кодировки, помеченные как 37 и M7 в этом документе.)

C: \> chcp 737
Активная кодовая страница: 737

C:\>echo αβγδεζ | od -t x1
0000000 98 99 9a 9b 9c 9d 20 0d 0a

C:\>perl -e "распечатать карту sprintf('%x ', ord($_)), split(//, $ARGV[0])" αβγδεζ
е1 е2 е3 е4 е5 е6

C:\>chcp 1253
Активная кодовая страница: 1253

C:\>echo αβγδεζ | od -t x1
0000000 e1 e2 e3 e4 e5 e6 20 0d 0a

C:\>perl -e "распечатать карту sprintf('%x ', ord($_)), split(//, $ARGV[0])" αβγδεζ
е1 е2 е3 е4 е5 е6

Если я помещаю символы в файл (из OS-X), скопируйте его в окно Windows (как file.txt), затем запустите:

perl -CI -e "chomp($_=<STDIN>); map{print ord, qq{\n}} split(//)" < file.txt

Тогда я получаю ожидаемое:

946
947
948
949
950

Но если я скопирую содержимое file.txt в командной строке, я получаю тарабарщину.

Как говорил @ikegami, я не думаю, что это можно сделать из командной строки, так как у вас нет локали UTF-8.

Это сработало для меня (на OS-X, но должно быть переносимым):

echo  αβγδεζ |perl -CI -e "chomp($in=<STDIN>);for (my $i = 0; $i < length($in); $i++) {print ord(substr($in, $i, 1)), qq{\n}; }"

Это было для STDIN; для ARGV:

perl -CA -e "for (my $i = 0; $i < length($ARGV[0]); $i++) {print ord(substr($ARGV[0], $i, 1)), qq{\n}; }" αβγδεζ

Увидеть -C опция в perlrun: http://perldoc.perl.org/perlrun.html

Вы можете попробовать использовать https://metacpan.org/pod/Win32::Unicode::Native. Он должен иметь то, что вам нужно.

Другие вопросы по тегам