Как декодировать аргументы Python Unicode?

Используя следующий код (на PHP), я отправляю строку в программу на Python:

shell_exec("python3 /var/www/html/app.py \"$text\"");

$text переменная содержит неанглийскую строку. Проблема в том, когда я печатаю аргументы в Python с print(sys.argv) Я получаю такой результат:

['/var/www/html/app.py', '\udcd8\udca8\udcd8\udcaa\udcd8\udcb5\udcd8\udcb4\udcda\udca9 \udcd8\udcae\udcd8\udcab\udcd9\udc87\udcd8\udca8 \udcd8\udcaa\udcd8\udcb4\udcd8\udcb5\udcd8\udcab']

Как я могу преобразовать эту строку Unicode в исходную форму текста в Python?

0

Решение

Python использует кодировку вашей локали для декодирования байтов, которые он получает из командной строки. Язык по умолчанию C использует ascii. $text похоже в utf-8. Поэтому Python должен использовать surrogateescape обработчик ошибок для декодирования этих байтов в текст sys.argv[1] который производит одинокие суррогаты, такие как '\udcd8' что вы видите на выходе.

Вы можете использовать UTF-8, например, LC_ALL=C.UTF-8 или перекодировать аргументы вручную: sys.argv[1].encode(locale.getpreferredencoding(True), 'surrogateescape').decode('utf-8'):

>>> s = u'\udcd8\udca8\udcd8\udcaa\udcd8\udcb5\udcd8\udcb4\udcda\udca9 \udcd8\udcae\udcd8\udcab\udcd9\udc87\udcd8\udca8 \udcd8\udcaa\udcd8\udcb4\udcd8\udcb5\udcd8\udcab'
>>> print(s.encode('ascii', 'surrogateescape').decode('utf-8'))
بتصشک خثهب تشصث
2

Другие решения

shell_exec("python3 /var/www/html/app.py \"$text\"");

(Я надеюсь $text сильно дезинфицировано, экранировано или статично! Если пользовательский ввод попал сюда, вы получаете ужасную уязвимость удаленного выполнения кода!)

'\udcd8\udca8\udcd8\udcaa\udcd8\udcb5\udcd8...

Хорошо, что здесь произошло, так это то, что PHP передал в Python строку в кодировке UTF-8, но Python не знал, что ввод командной строки был UTF-8. (Часто, когда вы запускаете Python в качестве команды, он может работать с вашим терминалом, но нет терминала, если он запускает Python на веб-сервере.)

Не зная, что вход был по умолчанию, равным ASCII. Старшие байты во входных данных недопустимы в ASCII, но Python 3 имеет обработчик отката «surrogateescape» для недопустимых байтов, который применяется к командной строке при декодировании его в строку Unicode. Это генерирует недопустимые в противном случае единицы суррогатного кода UTF-16 U + DC80 – U + DCFF, но, по крайней мере, позволяет восстановить исходные старшие байты, если вы хотите.

Так что либо:

  • установить PYTHONIOENCODING переменная среды для UTF-8 перед выполнением Python, так что он знает, что такое правильная кодировка, или

  • изменить скрипт Python для предварительной обработки его ввода, чтобы восстановить правильный ввод с sys.argv[1].encode('utf-8', 'surrogateescape').decode('utf-8')

2

По вопросам рекламы [email protected]