Python 3.4 — удалить или игнорировать символы смайликов при записи в файл

Я пытаюсь проанализировать файл XML и записать содержимое в обычный текстовый файл. У меня программа работает до тех пор, пока не наткнется на символ смайлика, затем Python выдает следующую ошибку:

UnicodeEncodeError: 'charmap' codec can't encode characters in position 177-181: character maps to <undefined>

Я пошел к месту ошибки и нашел следующие смайлики в файле XML:

эмодзи

Мой вопрос заключается в том, как либо закодировать их в Unicode, либо полностью удалить/игнорировать их при записи в файл.

Он отлично выводится, когда я печатаю () на консоль, но выдает ошибку при записи в файл.

Я искал в Google и здесь, но единственные ответы, которые я получаю, это то, что они уже закодированы в Unicode. Мои, как видите, литералы? Я не уверен, правильно ли я говорю.

Также файл XML, с которым я работаю, имеет следующий формат:

<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
<?xml-stylesheet type="text/xsl" href="sms.xsl"?>
<smses count="1">
  <sms protocol="0" address="+00000000000" date="1346772606199" type="1" subject="null" body="Lorem ipsum dolor sit amet, consectetur adipisicing elit," toa="null" sc_toa="null" service_center="+00000000000" read="1" status="-1" locked="0" date_sent="1346772343000" readable_date="Sep 4, 2012 10:30:06 AM" contact_name="John Doe" />
</smses>

person Francisco Mateo    schedule 19.05.2014    source источник
comment
Не могли бы вы использовать try: и except:, чтобы поймать ошибку?   -  person Harvey    schedule 19.05.2014
comment
Какой код вы используете для записи вывода в данный момент? Выбранная вами кодировка файла не поддерживает кодовые точки; вы можете выбрать другую кодировку или выбрать обработку ошибок.   -  person Martijn Pieters    schedule 19.05.2014
comment
Я бы сказал, что это не плохое предложение. Перебираем все символы и пытаемся их написать.   -  person RGS    schedule 19.05.2014
comment
@RSerrao: есть намного лучшие способы справиться с этим, чем обрабатывать символы один за другим.   -  person Martijn Pieters    schedule 19.05.2014
comment
@MartijnPieters Я начинающий программист на Python, поэтому, если бы вы могли меня просветить, я был бы рад!   -  person RGS    schedule 19.05.2014
comment
@RSerrao: нам нужно посмотреть, как OP пишет текст, но вы можете установить режим ошибки для действий и файлов кодирования.   -  person Martijn Pieters    schedule 19.05.2014
comment
@MartijnPieters, для меня это китайский язык ... знаете ли вы, что я могу найти в Google / где прочитать об этом?   -  person RGS    schedule 19.05.2014
comment
Можете ли вы показать нам часть кода, которая открывает выходной файл и записывает в него текст?   -  person Russell Borogove    schedule 19.05.2014
comment
@RSerrao: теперь есть ответ ниже; давайте посмотрим, сколько мне нужно настроить, как только мы узнаем, как OP открывает файл для записи.   -  person Martijn Pieters    schedule 19.05.2014
comment
@MartijnPieters Хорошо, спасибо. И последнее... Под ОП вы имеете в виду?   -  person RGS    schedule 19.05.2014
comment
@RSerrao: исходный постер; автор вопроса.   -  person Martijn Pieters    schedule 19.05.2014
comment
@MartijnPieters Хорошо. Спасибо, что поделились информацией.   -  person RGS    schedule 19.05.2014


Ответы (2)


У вас есть два варианта:

  1. Выберите кодировку, которая может обрабатывать кодовые точки Emoji. Вы открыли свой файл для записи либо с кодеком по умолчанию (который зависит от вашей системы), либо выбрали явную кодировку, которая не поддерживает кодовые точки.

    Кодировка UTF прекрасно справляется с кодовыми точками; Я бы выбрал UTF-8 здесь:

    with open(filename, 'w', encoding='utf8') as outfile:
        outfile.write(yourdata)
    
  2. Установите режим обработки ошибок, который либо заменяет кодовые точки, которые ваш кодек не может обработать, замещающими символами, управляющей последовательностью, либо полностью их игнорирует. См. аргумент open() function errors:

    errors — необязательная строка, указывающая, как должны обрабатываться ошибки кодирования и декодирования. Ее нельзя использовать в двоичном режиме. Доступны различные стандартные обработчики ошибок, хотя любое имя обработки ошибок, зарегистрированное с помощью codecs.register_error(), также допустимо. Стандартные названия:

    • 'strict' to raise a ValueError exception if there is an encoding error. The default value of None has the same effect.
    • 'ignore' игнорирует ошибки. Обратите внимание, что игнорирование ошибок кодирования может привести к потере данных.
    • 'replace' приводит к тому, что маркер замены (например, '?') вставляется там, где есть искаженные данные.
    • 'surrogateescape' будет представлять любые неправильные байты как кодовые точки в области частного использования Unicode в диапазоне от U+DC80 до U+DCFF. Эти частные кодовые точки затем будут преобразованы обратно в те же байты, когда при записи данных используется обработчик ошибок surrogateescape. Это полезно для обработки файлов в неизвестной кодировке.
    • 'xmlcharrefreplace' поддерживается только при записи в файл. Символы, не поддерживаемые кодировкой, заменяются соответствующей ссылкой на символ XML &#nnn;.
    • 'backslashreplace' (поддерживается только при записи) заменяет неподдерживаемые символы управляющими последовательностями Python с обратной косой чертой.

    Таким образом, открытие файла с errors='ignore' не запишет кодовые точки эмодзи вместо того, чтобы вызвать ошибку:

    with open(filename, 'w', errors='ignore') as outfile:
        outfile.write(yourdata)
    

Демо:

>>> a_ok = 'The U+1F44C OK HAND SIGN codepoint: \U0001F44C'
>>> print(a_ok)
The U+1F44C OK HAND SIGN codepoint: ????
>>> a_ok.encode('utf8')
b'The U+1F44C OK HAND SIGN codepoint: \xf0\x9f\x91\x8c'
>>> a_ok.encode('cp1251', errors='ignore')
b'The U+1F44C OK HAND SIGN codepoint: '
>>> a_ok.encode('cp1251', errors='replace')
b'The U+1F44C OK HAND SIGN codepoint: ?'
>>> a_ok.encode('cp1251', errors='xmlcharrefreplace')
b'The U+1F44C OK HAND SIGN codepoint: &#128076;'
>>> a_ok.encode('cp1251', errors='backslashreplace')
b'The U+1F44C OK HAND SIGN codepoint: \\U0001f44c'

Обратите внимание, что параметр 'surrogateescape' имеет ограниченное пространство и действительно полезен только для декодирования файла с неизвестной кодировкой, насколько это возможно; в любом случае он не может обрабатывать Emoji.

person Martijn Pieters    schedule 19.05.2014
comment
Ваши первые предложения отлично работают с первого раза. Благодарю вас! Я только начал изучать Python самостоятельно после того, как в течение года изучал Java в колледже. - person Francisco Mateo; 19.05.2014

(Изменить: этот ответ относится к Python 2.x, а не к Python 3.x)

В настоящее время вы записываете строки Unicode в файл с кодировкой по умолчанию, которая не поддерживает эмодзи (или, если уж на то пошло, массу символов, которые вам, вероятно, действительно нужны). Вместо этого вы можете использовать кодировку UTF-8, которая поддерживает все символы Юникода.

Вместо file.write( data ) попробуйте file.write( data.encode("utf-8") ).

person Russell Borogove    schedule 19.05.2014
comment
Это Python 3; файловые объекты обрабатывают кодировку. Это означает, что вы не хотите записывать закодированные байты. - person Martijn Pieters; 19.05.2014
comment
Ах, извините, не понял, что это Python 3. Хотите ответить? - person Russell Borogove; 19.05.2014
comment
Я хотел, чтобы ОП, желательно, дал мне, как он пишет в файл. - person Martijn Pieters; 19.05.2014