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

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

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

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

97
223
63
100
101
63

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


person Diomidis Spinellis    schedule 19.10.2011    source источник
comment
Это может вам не помочь, но из любопытства я попробовал на своем терминале Linux использовать UTF-8 с Perl 5.12.4. После изменения стиля цитирования на одинарные кавычки, чтобы оболочка не интерпретировала переменные $, которые я получил: 206 177 206 178 206 179 206 180 206 181 206 182 - я проверил первую букву альфа и она верна, поэтому я думаю, что это правильный результат.   -  person stivlo    schedule 19.10.2011
comment
Одинарные кавычки не работают в Windows, и я считаю, что правильными результатами будут 945 946 947 948 949 950 (tlt.its.psu.edu/suggestions/international/bylanguage/)   -  person MisterEd    schedule 19.10.2011
comment
Как вы вводили символы в командной строке? Вы копировали и вставляли из какой-то другой программы?   -  person Sinan Ünür    schedule 19.10.2011
comment
@MisterEd да, ты прав. Мой вывод не потерял никакой информации, но представляет собой побайтовый вывод, а не посимвольный вывод, который я могу получить с помощью переключателя -CA, как вы предложили. Рад, что чему-то научился, спасибо.   -  person stivlo    schedule 19.10.2011


Ответы (4)


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

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

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

  • a 97
  • ß 223
  • ? 63
  • d 100
  • e 101
  • ? 63

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

  1. Широкий интерфейс не используется, когда вы вводите команду в командной строке.
  2. Perl использует интерфейс ANSI для получения параметров, поэтому, даже если вы запустите Perl с использованием интерфейса Wide, параметры будут понижены до 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
Active code page: 737

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

C:\>perl -e "print map sprintf('%x ', ord($_)), split(//, $ARGV[0])" αβγδεζ
e1 e2 e3 e4 e5 e6

C:\>chcp 1253
Active code page: 1253

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

C:\>perl -e "print map sprintf('%x ', ord($_)), split(//, $ARGV[0])" αβγδεζ
e1 e2 e3 e4 e5 e6
person ikegami    schedule 19.10.2011
comment
@Диомидис Спинеллис. Я отменяю ваши изменения, потому что chcp использует кодовую страницу OEM, но я полагаю, что Perl получает аргументы, закодированные с использованием кодовой страницы ANSI. chcp будет работать, только если они совпадают. - person ikegami; 20.10.2011
comment
Вы правы относительно chcp, и я привел пример, чтобы проиллюстрировать это. Существует много кодовых страниц OEM, и выбор правильной из них обеспечивает решение. Я изменил ответ соответственно; Надеюсь, вы согласны. - person Diomidis Spinellis; 20.10.2011
comment
@Diomidis Spinellis, у меня только что было время, чтобы быстро просмотреть, но если я правильно угадываю, что вы говорите, это очень интересная и полезная информация. Подробно прочитаю завтра. Спасибо! - person ikegami; 20.10.2011

Это сработало для меня (на 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; для АРГВ:

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#Command-Switches

person MisterEd    schedule 19.10.2011
comment
Прости. Я получаю 97 искаженных символов UTF-8 (неожиданный непродолжительный байт 0x3f, сразу после стартового байта 0xdf) в строке ord at -e 1. 0 100 101 63 Это проблема командной строки Windows, я уверен, что она отлично работает в Linux. , Mac OS X и т. д. - person Diomidis Spinellis; 19.10.2011
comment
Интересно, интересно, связано ли это с командной строкой Windows. Работает ли это, если символы читаются из файла и/или если код помещается в скриптовый порок -e? - person MisterEd; 19.10.2011
comment
где вы запускаете свой скрипт? изнутри оболочки cmd? Если да, пробовали ли вы запускать cmd с ключом /U? - person stivlo; 19.10.2011
comment
Это не портативно. Это работает только в локалях UTF-8. У ОП определенно нет локали UTF-8. - person ikegami; 19.10.2011

Если я помещаю символы в файл (из 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.

person MisterEd    schedule 19.10.2011