Отказ от ответственности: Я согласен, что синтаксический анализ HTML лучше всего выполнять с использованием анализатора HTML.Тем не менее, автор специально попросил найти решение для регулярных выражений, и эта конкретная проблема представляет собой хороший способ продемонстрировать умную (и малоизвестную) технику регулярных выражений, которая очень удобна.
Но сначала есть логикаошибка в исходной функции.Он слепо выполняет числовую замену, которая приводит к ошибочным результатам, когда ШИРИНА точно равна половине ВЫСОТЫ, например, учитывая следующее:
<img src = "/" width="10" height="20" />
Исходная опубликованная программа возвращает следующий ошибочный результат:
<img src = "/" width="40" height="40" />
Проблема в том, что WIDTH удваивается вдвое.Для обеспечения правильной замены необходима дополнительная логика.
Крутой трюк с регулярными выражениями, которого вы, возможно, не знаете:
Вот модифицированная версия исходной программы, которая исправляет вышеупомянутую ошибку и включает в себя (прокомментировано) версия улучшенного регулярного выражения:
import re
s = '<img src = "/" width="10" height="111" />'
def a(x):
b = x.group(0)
if x.group(1):
b = b.replace(x.group(1),
"width=\""+ str(int(x.group(2))*2) +"\"")
if x.group(3):
b = b.replace(x.group(3),
"width=\""+ str(int(x.group(4))*2) +"\"")
return b
reobj = re.compile(r'''
<img # Start of IMG tag.
(?: # Group for multiple attributes.
\s+ # Attributes separated by whitespace.
(?: # Group for attribute alternatives.
(width\s*=\s*"(\d+)") # $1: WIDTH attribute, $2 value.
| (height\s*=\s*"(\d+)") # $3: HEIGHT attribute, $4 value.
|[^\s>]+) # Other IMG attributes.
)+ # One or more attributes.
[^>]*> # End of IMG tag.
''', re.IGNORECASE | re.VERBOSE)
ss = re.sub(reobj, a, s)
print ss
Обратите внимание, что WIDTH попадает в группы $ 1 и $ 2, а HEIGHT в группы $ 3 и $ 4, даже если их порядок в целевой строке меняется на обратный.Хотел бы я сказать, что я придумал этот крутой трюк, но я этого не сделал.Я украл его из одного из отличных постов Стивена Левитана: Получение нескольких необязательных значений атрибутов HTML .Довольно изящно, а?
Более чистое решение для регулярных выражений
Как бы умно это ни было, оно все же сложнее, чем нужно для этой работы.Я хотел бы сделать это простым и просто сделать две отдельные операции замены следующим образом:
import re
s = '<img src = "/" width="10" height="111" />'
def a(x):
return x.group(1) + str(int(x.group(2))*2)
ss = re.sub(r"(?i)(<img[^>]*?width\s*=\s*[\"'])(\d+)",a, s)
ss = re.sub(r"(?i)(<img[^>]*?height\s*=\s*[\"'])(\d+)",a, ss)
print ss
Меньше.чище, легче для чтения и, вероятно, самое быстрое решение.(Обратите внимание, что функция обратного вызова становится тривиальной.)