Страницы

Поиск по вопросам

воскресенье, 9 февраля 2020 г.

punycode. передача пременной из bash в python в функцию encode('idna')

#python #bash #encoding #python_27


существует файл py1 c следующим содержанием:

python -c "x=u'''$1''';  print x.encode('idna')"


буква u, в начале значения для переменной  - это попытка привести ввод в 
bash

./py1 подпись.рф


к следующему виду в python:

x=u"подпись.рф"


так вот, при вызове скрипта получаем следующий вывод:

~$ ./py1 а
xn--nba1k
~$ ./py1 апо
xn--34-eea4dwnbb5725d


но:

~$ ./py1 ф
Traceback (most recent call last):
File "", line 1, in 
File "/usr/lib/python2.7/encodings/idna.py", line 164, in encode
result.append(ToASCII(label))
File "/usr/lib/python2.7/encodings/idna.py", line 76, in ToASCII
label = nameprep(label)
File "/usr/lib/python2.7/encodings/idna.py", line 38, in nameprep
raise UnicodeError("Invalid character %r" % c)
UnicodeError: Invalid character u'\x84'


ошибка по-видимому в данном месте 

u'''$1'''


и возможно логичнее было бы воспользоваться sys.argv[] в python, однако я никак не
возьму в толк, как верно вставить полученную переменную в python из sys.agr в другую,
с параметром u перед строкой, пробовал следующий подход:

создается файл wpq1.py с нижеизложенным:

# -*- coding: UTF-8 -*-
import sys

x= unicode(sys.argv[1])
print x


затем вызывается в shell:

~$ python wpy1.py фырфырфыр
Traceback (most recent call last):
File "wpy1.py", line 5, in 
x= unicode(sys.argv[1])
UnicodeDecodeError: 'ascii' codec can't decode byte 0xd1 
in position 0: ordinal not in range(128)

    


Ответы

Ответ 1



В Питоне 3 sys.argv уже как Unicode пришёл бы: $ python3 -c 'import sys; print(sys.argv[1].encode("idna").decode())' пример.рф xn--e1afmkfd.xn--p1ai В Питоне 2, самостоятельно аргументы командной строки из байт в текст декодировать необходимо. Для этого нужно выбрать кодировку. Для системных строк: argv, переменных окружения, путей можно sys.getfilesystemencoding() кодировку использовать (с оговорками): $ python2 -c 'import sys; print sys.argv[1].decode(sys.getfilesystemencoding()).encode("idna")' пример.рф xn--e1afmkfd.xn--p1ai На Linux sys.getfilesystemencoding() от локали зависит. Подробнее Как работать с путями c русскими символами? В общем случае, системные строки это почти произвольный набор байт, который не всегда как текст можно интерпретировать, поэтому существует surrogateescape обработчик ошибок, который также может активироваться на Python 3, если локаль не настроена (или неверно настроена): $ LC_ALL=C python3 -c 'import sys; print(sys.argv[1].encode("idna").decode())' пример.рф Traceback (most recent call last): File "/usr/lib/python3.5/encodings/idna.py", line 181, in encode result.extend(ToASCII(label)) File "/usr/lib/python3.5/encodings/idna.py", line 76, in ToASCII label = nameprep(label) File "/usr/lib/python3.5/encodings/idna.py", line 38, in nameprep raise UnicodeError("Invalid character %r" % c) UnicodeError: Invalid character '\udcd0' Локаль по умолчанию (поломанные или вообще отсутствующие настройки) подразумевает ascii кодировку (С, POSIX). Поэтому при запуске init-скриптов (сервисы), при заходе по ssh, в cron-скриптах, убедитесь что локаль c нужной кодировкой определена, чтобы не-ascii содержимое такое как IDN обрабатывать. Иначе ошибку получите: $ LC_ALL=C python2 -c 'import sys; print sys.argv[1].decode(sys.getfilesystemencoding()).encode("idna")' пример.рф Traceback (most recent call last): File "", line 1, in UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128) Если вы решите жёстко прописать кодировку такую как utf-8, то будьте уверены на 100%, что имена доменов у вас всегда всегда в этой кодировке генерируются в окружении, где вы запускаете ваш Питон-скрипт. Иначе или UnicodeDecodeError или хуже кракозябры получите, что приведёт к генерации неверного punycode (что вы можете не сразу заметить, что удорожает исправление ошибки).

Ответ 2



Не особо много знаю о пайтоне, но, погуглив документацию, заметил, что функция unicode имеет второй параметр для указания кодировки. Так что вот такой вариант рабоает в моей консоли (Ubuntu 16.04, UTF-8): import sys x = unicode(sys.argv[1], 'utf-8') print x print x.encode('idna')

Комментариев нет:

Отправить комментарий