Используя следующий код (на 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?
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'))
بتصشک خثهب تشصث
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')