Как избежать специальных символов Unicode в строке и записать их в файл с кодировкой UTF

Чего я хочу добиться, так это:

строка типа:

Bitte überprüfen Sie, ob die Dokumente erfolgreich in System eingereicht wurden, und löschen Sie dann die tatsächlichen Dokumente.

преобразовать в:

'Bitte \u00FCberpr\u00FCfen Sie, ob die Dokumente erfolgreich in System eingereicht wurden, und l\u00F6schen Sie dann die tats\u00E4chlichen Dokumente.'

и запишите его в таком виде в файл (в кодировке UTF-8).


person PiWo    schedule 15.07.2021    source источник
comment
Попробуйте repr() преобразовать его?   -  person sabik    schedule 15.07.2021
comment
repr() создает ту же строку — вы имели в виду что-то особенное?   -  person PiWo    schedule 15.07.2021


Ответы (2)


Другое решение, не полагающееся на встроенный repr(), а реализующее его с нуля:

orig = 'Bitte überprüfen Sie, ob die Dokumente erfolgreich in System eingereicht wurden, und löschen Sie dann die tatsächlichen Dokumente.'

enc = re.sub('[^ -~]', lambda m: '\\u%04X' % ord(m[0]), orig)

print(enc)

Отличия:

  • Кодирует только с использованием \u, а не какой-либо другой последовательности, тогда как repr() использует около трети алфавита (так, например, символ BEL будет кодироваться как \u0007, а не \a)
  • Кодировка верхнего регистра, как указано (\u00FC вместо \u00fc)
  • Не обрабатывает символы Юникода за пределами плоскости 0 (можно легко расширить, учитывая спецификацию того, как они должны быть представлены)
  • Он не заботится о каких-либо ранее существовавших последовательностях \u, тогда как repr() превращает их в \\u; может быть расширен, возможно, для кодирования \ как \u005C:
    enc = re.sub(r'[^ -[\]-~]', lambda m: '\\u%04X' % ord(m[0]), orig)
    
person sabik    schedule 15.07.2021
comment
Это очень чистое решение. Спасибо :) Именно то, что мне нужно. Он фактически преобразует некоторый символ, которого не делал метод ascii, например. : „” - person PiWo; 16.07.2021

Простым решением будет ascii():

string = 'Bitte überprüfen Sie, ob die Dokumente erfolgreich in System ' \
         'eingereicht wurden, und löschen Sie dann die tatsächlichen Dokumente.'

print(ascii(string))

выход :

'Bitte \xfcberpr\xfcfen Sie, ob die Dokumente erfolgreich in System eingereicht wurden, und l\xf6schen Sie dann die tats\xe4chlichen Dokumente.'

Также для этого можно использовать unicode-escape и raw-unicode-escape (ссылка ):

string = 'Bitte überprüfen Sie, ob die Dokumente erfolgreich in System ' \
         'eingereicht wurden, und löschen Sie dann die tatsächlichen Dokumente.'

print(string.encode('unicode-escape').decode('raw-unicode-escape'))

выход :

Bitte \xfcberpr\xfcfen Sie, ob die Dokumente erfolgreich in System eingereicht wurden, und l\xf6schen Sie dann die tats\xe4chlichen Dokumente.

Примечание: ascii() экранирует не-ascii-символы с помощью \x , \u, \U для 1 байта, 2 байтов и 4 байтов соответственно. В вашем случае вы видите \x. Но попробуйте этот:

print(ascii('س'))  # '\u0633'

Если вы действительно хотите преобразовать escape-последовательности \xhh в \u00hh , используйте re.sub() в результате ascii():

import re
print(re.sub(r'\\x[a-f0-9]{2}', lambda x: r'\u00' + x.group()[-2:].upper(), ascii(string))) 

выход :

'Bitte \u00FCberpr\u00FCfen Sie, ob die Dokumente erfolgreich in System eingereicht wurden, und l\u00F6schen Sie dann die tats\u00E4chlichen Dokumente.'

Вышеупомянутые подходы работают для экранирования любых символов, отличных от ascii, если вы собираетесь экранировать только эти три немецких алфавита и нет других символов, отличных от ascii, взгляните на str.translate().

person SorousH Bakhtiary    schedule 15.07.2021
comment
Привет, спасибо за ответ! Пока он работает, он выдает символ \x вместо символов \u, что будет проблемой в дальнейшем процессе (файл будет обрабатываться другой программой/языком программирования). Любая идея, как заставить символ \u? Например. 'ü' == 'ü' == '\xfc' - person PiWo; 15.07.2021
comment
@PiWo, честно говоря, я не знаю, когда ascii() генерирует \x, а когда \u. В последнем случае print(ascii('س')) мы видим \u. Если вы используете те кодировки, которые я упомянул в ответе, у вас все еще есть проблема? Разве он не конвертирует обратно в символы правильно? - person SorousH Bakhtiary; 15.07.2021
comment
Программа, которая читает конечный продукт, должна иметь жестко закодированную таблицу преобразования символов юникода (она была написана на Коболе, у меня нет исходников), и она ожидает нотацию \u. https://stackoverflow.com/a/46132950/1216005 более менее объясняет, что это просто более короткая запись - у меня будет что-то выяснить. - person PiWo; 15.07.2021
comment
@PiWo Я добавил регулярное выражение для преобразования этих \xhh в \u00hh. Теперь это ожидаемый результат, но я не уверен, что это лучшее решение. - person SorousH Bakhtiary; 15.07.2021
comment
Я сделал что-то похожее с .replace('\x', '\u00'). Это не чисто, но пока работает, поскольку это уникальная проблема для этой конкретной ситуации. Благодарю вас! - person PiWo; 15.07.2021
comment
Единственным предостережением при этом будет то, что строка изначально содержит \x, которая будет закодирована как \\x, но не должна не преобразовываться в \\u00 - person sabik; 15.07.2021
comment
Кроме того, вопрос задавался в верхнем регистре, \u00FC, а не \u00fc; не уверен, что это имеет значение - person sabik; 15.07.2021
comment
@sabik Спасибо за упоминание, я обновил ответ. - person SorousH Bakhtiary; 15.07.2021
comment
(Не забудьте также обновить вывод примера для обновленного кода.) - person sabik; 15.07.2021
comment
Поскольку замена становится все более сложной, она постепенно сходится с подходом к пропуску ascii() и выполнению re.sub() в исходной строке... - person sabik; 15.07.2021
comment
@сабик лол. или еще лучше str.translate(), если ему просто нужно это экранирование для германских алфавитов. - person SorousH Bakhtiary; 15.07.2021