Другой подход, который намного быстрее, чем ответ выше, заключается в использовании регулярных выражений, например, так:
re.sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', '', text)
По сравнению с ответом выше, в моем тестировании это происходит более чем в 10 раз:
import timeit
func_test = """
def valid_xml_char_ordinal(c):
codepoint = ord(c)
# conditions ordered by presumed frequency
return (
0x20 <= codepoint <= 0xD7FF or
codepoint in (0x9, 0xA, 0xD) or
0xE000 <= codepoint <= 0xFFFD or
0x10000 <= codepoint <= 0x10FFFF
);
''.join(c for c in r.content if valid_xml_char_ordinal(c))
"""
func_setup = """
import requests;
r = requests.get("/5536099/filtratsiya-opredelennyh-baitov-v-python")
"""
regex_test = """re.sub(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', '', r.content)"""
regex_setup = """
import requests, re;
r = requests.get("/5536099/filtratsiya-opredelennyh-baitov-v-python")
"""
func_test = timeit.Timer(func_test, setup=func_setup)
regex_test = timeit.Timer(regex_test, setup=regex_setup)
print func_test.timeit(100)
print regex_test.timeit(100)
Вывод:
> 2.63773989677
> 0.221401929855
Итак, чтобы понять это, мы загружаем эту веб-страницу один раз (страницу, которую вы сейчас читаете), затем запускаете функционалтехника и метод регулярных выражений по его содержимому 100X каждый.
Использование функционального метода занимает около 2,6 секунд.
Использование метода регулярных выражений занимает около 0,2 секунд.
Обновление : Как указано в комментариях, регулярное выражение в этом ответе ранее удалило некоторые символы, которые должны были быть разрешены в XML.Эти символы включают в себя что-либо на дополнительной многоязычной плоскости , которая включает древние сценарии, такие как клинопись, иероглифы и (странно) эмодзи.
Правильное регулярное выражение теперь вышеБыстрый тест для этого в будущем использует re.DEBUG
, который печатает:
In [52]: re.compile(u'[^\u0020-\uD7FF\u0009\u000A\u000D\uE000-\uFFFD\U00010000-\U0010FFFF]+', re.DEBUG)
max_repeat 1 4294967295
in
negate None
range (32, 55295)
literal 9
literal 10
literal 13
range (57344, 65533)
range (65536, 1114111)
Out[52]: re.compile(ur'[^ -\ud7ff\t\n\r\ue000-\ufffd\U00010000-\U0010ffff]+', re.DEBUG)
Мои извинения за ошибку.Я могу только предложить, что я нашел этот ответ в другом месте и поместил его здесь.Это была чужая ошибка, но я ее размножил.Мои искренние извинения всем, кого это затронуло.
Обновление 2, 2017-12-12 : я узнал от некоторых пользователей OSX, что этот код не будет работать на так называемых узких сборкахPython, который, по-видимому, OSX иногда имеет.Вы можете проверить это, запустив import sys; sys.maxunicode
.Если он напечатает 65535, код здесь не будет работать, пока вы не установите «широкую сборку». Подробнее об этом здесь.