Быстрый способ отфильтровать недопустимые символы XML Unicode в Python? - PullRequest
26 голосов
/ 10 ноября 2009

В спецификации XML перечислены группы символов Юникода, которые являются недопустимыми или "не рекомендуется". Учитывая строку, как я могу удалить все недопустимые символы из нее?

Я придумал следующее регулярное выражение, но оно немного глоток.

illegal_xml_re = re.compile(u'[\x00-\x08\x0b-\x1f\x7f-\x84\x86-\x9f\ud800-\udfff\ufdd0-\ufddf\ufffe-\uffff]')
clean = illegal_xml_re.sub('', dirty)

(Python 2.5 не знает о символах Unicode выше 0xFFFF, поэтому их не нужно фильтровать.)

Ответы [ 2 ]

17 голосов
/ 08 марта 2014

Недавно мы (Trac XmlRpcPlugin сопровождающие) были уведомлены о том факте, что приведенное выше регулярное выражение удаляет суррогатные пары в узких сборках Python (см. th: комментарий: 13: тикет: 11050 ) Альтернативный подход заключается в использовании следующего регулярного выражения (см. th: changeset: 13729 ).

_illegal_unichrs = [(0x00, 0x08), (0x0B, 0x0C), (0x0E, 0x1F), 
                        (0x7F, 0x84), (0x86, 0x9F), 
                        (0xFDD0, 0xFDDF), (0xFFFE, 0xFFFF)] 
if sys.maxunicode >= 0x10000:  # not narrow build 
        _illegal_unichrs.extend([(0x1FFFE, 0x1FFFF), (0x2FFFE, 0x2FFFF), 
                                 (0x3FFFE, 0x3FFFF), (0x4FFFE, 0x4FFFF), 
                                 (0x5FFFE, 0x5FFFF), (0x6FFFE, 0x6FFFF), 
                                 (0x7FFFE, 0x7FFFF), (0x8FFFE, 0x8FFFF), 
                                 (0x9FFFE, 0x9FFFF), (0xAFFFE, 0xAFFFF), 
                                 (0xBFFFE, 0xBFFFF), (0xCFFFE, 0xCFFFF), 
                                 (0xDFFFE, 0xDFFFF), (0xEFFFE, 0xEFFFF), 
                                 (0xFFFFE, 0xFFFFF), (0x10FFFE, 0x10FFFF)]) 

_illegal_ranges = ["%s-%s" % (unichr(low), unichr(high)) 
                   for (low, high) in _illegal_unichrs] 
_illegal_xml_chars_RE = re.compile(u'[%s]' % u''.join(_illegal_ranges)) 

p.s. См. этот пост о суррогатах , объясняющий, для чего они.

Обновление , чтобы не совпадать (заменить) 0x0D, который является действительным символом XML .

3 голосов
/ 10 ноября 2009

Вы также можете использовать метод перевода Unicode для удаления выбранных кодовых точек. Тем не менее, ваше отображение довольно большое (2128 кодовых точек), и это может сделать его намного медленнее, чем просто с помощью регулярного выражения:

ranges = [(0, 8), (0xb, 0x1f), (0x7f, 0x84), (0x86, 0x9f), (0xd800, 0xdfff), (0xfdd0, 0xfddf), (0xfffe, 0xffff)]
# fromkeys creates  the wanted (codepoint -> None) mapping
nukemap = dict.fromkeys(r for start, end in ranges for r in range(start, end+1))
clean = dirty.translate(nukemap)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...