Я получаю китайские иероглифы в выводах curl
, а затем передаю их в качестве входных данных для скрипта Python, но я получаю два совершенно разных поведения в зависимости от того, как я обрабатываю символы.
Метод, который я предпочитаю, дает мне UnicodeEncodeError.
Предпочтительный метод:
read -r C < <(curl ...)
python3 -c "import sys, urllib.parse; \
urllib.parse.quote(sys.argv[1])" "$C"
# UnicodeEncodeError: 'utf-8' codec can't encode character '\udce5' in position 0: surrogates not allowed
Альтернативный метод:
curl ... > tmp.txt
python3 -c "import urllib.parse; \
with open('tmp.txt', encoding='utf-8') as f: \
print(urllib.parse.quote(f.read()))"
# Outputs %E5%85%89%0A
Могу ли я что-нибудь сделать, чтобы первый метод, использующий переменную bash, работал? Когда я echo $C
или cat tmp.txt
, китайский иероглиф правильно печатается на моем терминале.
Когда я запускаю locale
на своей машине, я получаю:
LANG=
LANGUAGE=
LC_CTYPE = "POSIX"
LC_NUMERIC = "POSIX"
LC_TIME = "POSIX"
LC_COLLATE = "POSIX"
LC_MONETARY = "POSIX"
LC_MESSAGES = "POSIX"
LC_PAPER = "POSIX"
LC_NAME = "POSIX"
LC_ADDRESS = "POSIX"
LC_TELEPHONE = "POSIX"
LC_MEASUREMENT = "POSIX"
LC_IDENTIFICATION = "POSIX"
LC_ALL=
РЕДАКТИРОВАТЬ
Моя среда - крутон (в ChromeOS). Мой баш GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)
.
@Tomalak, возможно, это то направление, в котором я должен идти, но большая часть более крупной системы построена на сценариях bash, поэтому я не хотел переделывать. У вас есть идеи, почему я столкнулся с проблемой, опубликованной?
это сообщение об ошибке python сбивает с толку и сбивает с толку. если бы я мог понять, что это должно означать, я бы поднял отчет об ошибке.
«суррогаты не разрешены» просто означает, что кодирование суррогатных пар в UTF-8 недопустимо. Суть этих пар заключается в их использовании в UTF-16, где одна кодовая точка представлена одним или двумя 16-битными значениями. Кстати, поиск этой ошибки приводит к нескольким совпадениям. Тем не менее, вам нужно извлечь минимальный воспроизводимый пример, потому что не совсем понятно, что именно у вас есть в какой момент. Кроме того, на какой ОС вы работаете? Это может быть важно, потому что передача аргументов и их кодировок зависит от ОС (и сложна).
Как насчет того, чтобы избежать нежелательной обработки командной строки bash через curl | python
и чтения sys.stdin
в Python?
@UlrichEckhardt, я нахожусь в среде крутонов на ChromeOS. Я добавил редактирование выше с некоторыми подробностями на случай, если это вас заинтересует.
@Tomalak, мне не удалось переместить все в Python, потому что я использую библиотеку nodejs для другой части системы, и попытка открыть подпроцесс для nodejs, снабжая его китайским иероглифом из Python, приводит к тому же результату UnicodeEncodeError
.
Ваш код по-прежнему не позволяет воспроизвести проблему. Пожалуйста, прочитайте, что означает MCVE, и обратите внимание на мелкие детали.
python использует LC_CTYPE при интерпретации argv. установить локаль UTF8.
read -r C < <(curl ...)
LC_CTYPE='en_US.UTF8' python3 -c "import sys, urllib.parse; \
print(urllib.parse.quote(sys.argv[1]))" "$C"
В качестве альтернативы настройке LC_CTYPE
вы можете просто установить LANG
, в зависимости от того, не используют ли другие части вашей системы LC_CTYPE
.
или настроить один по умолчанию.
Если команда LC_CTYPE='en_US.UTF8'
приводит к ошибке, возможно, у вас не установлена локаль en_US.UTF8
(или любая другая выбранная вами локаль).
Вы можете проверить, какие локали установлены, запустив locale -a
. Чтобы установить локаль en_US.UTF8:
sudo locale-gen 'en_US'
sudo locale-gen 'en_US.UTF-8'
Спасибо, @Jasen, но даже ввод LC_CTYPE='en_US.UTF8'
приводит к ошибке: -su: warning: setlocale: LC_CTYPE: cannot change locale (en_US.UTF8)
Возможно, вам потребуется установить эту локаль, возможно, спросите, как это сделать для Chrome-os в режиме суперпользователя.
Спасибо. Это дало мне понимание, чтобы пройти большой путь туда. Пожалуйста, извините за редактирование.
Зачем завивать, когда вы можете запросить URL-адрес из Python?