Сделайте последовательность операторов string.replace более читабельной - PullRequest
3 голосов
/ 31 июля 2011

Когда я обрабатываю код HTML в Python, я должен использовать следующий код из-за специальных символов.

line = string.replace(line, """, "\"")
line = string.replace(line, "'", "'")
line = string.replace(line, "&", "&")
line = string.replace(line, "&lt;", "<")
line = string.replace(line, "&gt;", ">")
line = string.replace(line, "&laquo;", "<<")
line = string.replace(line, "&raquo;", ">>")
line = string.replace(line, "&#039;", "'")
line = string.replace(line, "&#8220;", "\"")
line = string.replace(line, "&#8221;", "\"")
line = string.replace(line, "&#8216;", "\'")
line = string.replace(line, "&#8217;", "\'")
line = string.replace(line, "&#9632;", "")
line = string.replace(line, "&#8226;", "-")

Кажется, таких специальных символов мне придется заменить гораздо больше.Вы знаете, как сделать этот код более элегантным?

спасибо

Ответы [ 3 ]

4 голосов
/ 31 июля 2011
REPLACEMENTS = [
    ("&quot;", "\""),
    ("&apos;", "'"),
    ...
    ]
for entity, replacement in REPLACEMENTS:
    line = line.replace(entity, replacement)

Обратите внимание, что string.replace просто доступен как метод для str / unicode объектов.

Еще лучше, проверьте этот вопрос !

Название вашего вопроса требует чего-то иного: оптимизации, то есть, чтобы она работала быстрее.Это совершенно другая проблема, и она потребует дополнительной работы.

2 голосов
/ 31 июля 2011

Оптимизация

REPL_tu = (("&quot;", "\"") , ("&apos;", "'") , ("&amp;", "&") ,
           ("&lt;", "<") , ("&gt;", ">") ,
           ("&laquo;", "<<") , ("&raquo;", ">>") ,
           ("&#039;", "'") ,
           ("&#8220;", "\"") , ("&#8221;", "\"") ,
           ("&#8216;", "\'") , ("&#8217;", "\'") ,
           ("&#9632;", "") , ("&#8226;", "-")     )

def repl(mat, d = dict(REPL_tu)):
    return d[mat.group()]

import re
regx = re.compile('|'.join(a for a,b in REPL_tu))

line = 'A tag &lt;bidi&gt; has a &quot;weird&#8220;&#8226;&apos;content&apos;'
modline = regx.sub(repl,line)
print 'Exemple:\n\n'+line+'\n'+modline 








from urllib import urlopen

print '\n-----------------------------------------\nDownloading a web source:\n'
sock = urlopen('http://www.mythicalcreaturesworld.com/greek-mythology/monsters/python-the-serpent-of-delphi-%E2%80%93-python-the-guardian-dragon-and-apollo/')
html_source = sock.read()
sock.close()

from time import clock

n = 100

te = clock()
for i in xrange(n):
    res1 = html_source
    res1 = regx.sub(repl,res1)
print 'with regex  ',clock()-te,'seconds'


te = clock()
for i in xrange(n):
    res2 = html_source
    for entity, replacement in REPL_tu:
        res2 = res2.replace(entity, replacement)
print 'with replace',clock()-te,'seconds'

print res1==res2

результат

Exemple:

A tag &lt;bidi&gt; has a &quot;weird&#8220;&#8226;&apos;content&apos;
A tag <bidi> has a "weird"-'content'

-----------------------------------------
Downloading a web source:

with regex   0.097578323502 seconds
with replace 0.213866846205 seconds
True
2 голосов
/ 31 июля 2011

Вот код, который я недавно написал для декодирования HTML-объектов. Обратите внимание, что это для Python 2.x, поэтому он также декодирует от str до unicode: вы можете сбросить этот бит, если вы используете современный Python. Я думаю, что он обрабатывает любые из названных объектов, десятичных и шестнадцатеричных объектов. По какой-то причине «апос» отсутствует в словаре именованных сущностей Python, поэтому я сначала скопировал его и добавил недостающий:

from htmlentitydefs import name2codepoint
name2codepoint = name2codepoint.copy()
name2codepoint['apos']=ord("'")

EntityPattern = re.compile('&(?:#(\d+)|(?:#x([\da-fA-F]+))|([a-zA-Z]+));')
def decodeEntities(s, encoding='utf-8'):
    def unescape(match):
        code = match.group(1)
        if code:
            return unichr(int(code, 10))
        else:
            code = match.group(2)
            if code:
                return unichr(int(code, 16))
            else:
                code = match.group(3)
                if code in name2codepoint:
                    return unichr(name2codepoint[code])
        return match.group(0)

    if isinstance(s, str):
        s = s.decode(encoding)
    return EntityPattern.sub(unescape, s)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...