Вывод текста Unicode в файл RTF в Python - PullRequest
4 голосов
/ 28 марта 2012

Я пытаюсь вывести текст Unicode в файл RTF из скрипта Python. Для фона Википедия говорит

Для экранирования Unicode используется управляющее слово \ u, за которым следует 16-разрядное целое число со знаком, дающее номер кодовой единицы Unicode UTF-16. В интересах программ без поддержки Unicode, это должно сопровождаться ближайшим представлением этого символа в указанной кодовой странице. Например, \ u1576? даст арабскую букву bāʼ ب, указывающую, что старые программы, которые не поддерживают Unicode, должны отображать его вместо знака вопроса.

Существует также этот вопрос о выводе RTF из Java и этот вопрос о том, как делать это в C # .

Однако я не могу понять, как вывести кодовую точку Unicode как «16-разрядное десятичное целое число со знаком с номером кодовой единицы Unicode UTF-16» из Python. Я пробовал это:

for char in unicode_string:
    print '\\' + 'u' + ord(char) + '?',

но вывод отображается только как бессмысленный при открытии в текстовом процессоре; проблема заключается в том, что это не кодовый номер UTF-16. Но не уверен, как это получить; хотя можно кодировать в utf-16, как получить кодовый номер?

Кстати, PyRTF не поддерживает Unicode (он указан как «todo»), и хотя pyrtf-NG должен это делать, этот проект, похоже, не поддерживается и имеет мало документации, поэтому я опасаюсь его в квазипроизводственной системе.

Редактировать: Моя ошибка. В приведенном выше коде есть две ошибки - как указано в Wobble ниже, строка должна быть строкой Unicode, а не уже закодированной, и приведенный выше код дает результат с пробелами между символами. Правильный код такой:

convertstring=""
for char in unicode(<my_encoded_string>,'utf-8'):
    convertstring = convertstring + '\\' + 'u' + str(ord(char)) + '?'

Это отлично работает, по крайней мере, с OpenOffice. Я оставляю это здесь как ссылку для других (одна ошибка была исправлена ​​после обсуждения ниже).

Ответы [ 2 ]

3 голосов
/ 28 марта 2012

На основании информации в вашем последнем редактировании, я думаю, что эта функция будет работать правильно. За исключением см. Улучшенную версию ниже.

def rtf_encode(unistr):
    return ''.join([c if ord(c) < 128 else u'\\u' + unicode(ord(c)) + u'?' for c in unistr])

>>> test_unicode = u'\xa92012'
>>> print test_unicode
©2012
>>> test_utf8 = test_unicode.encode('utf-8')
>>> print test_utf8
©2012
>>> print rtf_encode(test_utf8.decode('utf-8'))
\u169?2012

Вот еще одна версия, которая немного разбита, чтобы ее было легче понять. Я также сделал это последовательным в возвращении строки ASCII, вместо того, чтобы сохранять Unicode и отбрасывать его на join. Это также включает исправление, основанное на комментариях.

def rtf_encode_char(unichar):
    code = ord(unichar)
    if code < 128:
        return str(unichar)
    return '\\u' + str(code if code <= 32767 else code-65536) + '?'

def rtf_encode(unistr):
    return ''.join(rtf_encode_char(c) for c in unistr)
1 голос
/ 06 июня 2012

Ответ Марка Рэнсома не совсем корректен, так как он не будет правильно кодировать кодовые точки через U + 7fff и не будет экранировать символы ниже 0x20, как рекомендовано стандартом RTF.

Я создал простоймодуль, который кодирует Unicode Python в управляющие коды RTF, называемые rtfunicode, и написал о теме в моем блоге .

Таким образом, мой метод использует регулярное выражениечтобы сопоставить правильные кодовые точки с управляющими кодами RTF, подходящими для включения в PyRTF или pyrtf-ng.

...