У меня есть несколько сотен файлов разметки с блоками кода в них, и они выглядят примерно так.
'''html
<img src="fil.png">
'''
- [ ] Here is another image <img src="fil.png"> and another '<img src="fil.png">'
'''html
<a href="scratch/index.html" id="scratch" data-original-title="" title="" aria-describedby="popover162945">
<div class="logo-wrapper">
</div>
<div class="name">
<span>Scratch</span>
</div>
<img src="fil.png">
</a>
'''
Моя цель - найти все теги IMG без тега alt вне блоков кода.
Не уверен, могу ли я использовать HTML: парсер либо из-за кодовых блоков...
Я не ищу идеальное решение, просто что-то, что найдет простые теги img, охватывающие несколько строк.
'''html
<img src="fil.png">
'''
Не следует находить этот, так как он находится внутри блока img.
- [ ] Here is another image '<img src="fil.png">' and another <img src="dog.png" title: "re
aaaaaaaaaaaaaaaallllyl long title">
Нельзя найти первую (как она окружена), однако она должна найти вторую, даже если она охватывает несколько строк.
Я пробовал несколько разных методов, используя все: от bash и grep до python. Я могу получить теги img
используя следующее regex
<img(\s*(?!alt)([\w\-])+=([\"\'])[^\"\']+\3)*\s*\/?>
Однако я считаю, что более чистым подходом может быть
Я немного застрял на первом шаге. Я могу найти каждый блок кода, используя это регулярное выражение:
'''[a-z]*\n[\s\S]*?\n'''
Однако я не уверен, как инвертировать это, например, найти весь текст за его пределами. Я бы принял любые решения, которые можно запустить в сценарии bash или из python.
Вы абсолютно правы, это классический случай для подхода regex trashcan: Мы * ПРОПУСКАЕМ, что следует избегать в общем матче, и использовать группу захвата для того, что мы действительно хотим, т.е. What_I_want_to_avoid|(What_I_want_to_match)
:
'''.*?'''|'.*?'|(<img(?!.*?alt=(['\"]).*?\2)[^>]*)(>)
Идея здесь состоит в том, чтобы полностью игнорировать общие совпадения, возвращаемые движком регулярных выражений: это мусорный ящик. Вместо этого нам нужно только проверить группу захвата $ 1, которая, когда установлена, содержит img-теги.
Здесь заимствован шаблон для соответствия img-тегам без атрибута alt. Метод trashcan описан здесь и здесь.
import re
regex = r"'''.*?'''|'.*?'|(<img(?!.*?alt=(['\"]).*?\2)[^>]*)(>)"
test_str = ("'''html\n"
"<img src=\"fil.png\">\n"
"'''\n\n"
"- [ ] Here is another image <img src=\"fil.png\"> and another '<img src=\"fil.png\">'\n\n"
" '''html\n"
" <a href=\"scratch/index.html\" id=\"scratch\" data-original-title=\"\" title=\"\" aria-describedby=\"popover162945\">\n"
" <div class=\"logo-wrapper\">\n"
" </div>\n"
" <div class=\"name\">\n"
" <span>Scratch</span>\n"
" </div>\n"
" <img src=\"fil.png\">\n"
" </a>\n"
" '''")
matches = re.finditer(regex, test_str, re.DOTALL)
for match in matches:
if match.group(1):
print ("Found at {start}-{end}: {group}".format(start = match.start(1), end = match.end(1), group = match.group(1)))
На самом деле, достаточно было бы просто поставить одну парную парную спину в полном матче. Однако это, возможно, более читаемо и демонстрирует идею более ясную, как показано выше.
Мой подход заключается в удалении всех строк между "'"
, а затем просто отправьте текст в BeautifulSoup для синтаксического анализа (я найду все теги img
без атрибута alt
и распечатаю его src
):
data = """
'''html
<img src="fil.png">
'''
- [ ] Here is another image <img src="fil.png"> and another '<img src="fil.png">'
'''html
<a href="scratch/index.html" id="scratch" data-original-title="" title="" aria-describedby="popover162945">
<div class="logo-wrapper">
</div>
<div class="name">
<span>Scratch</span>
</div>
<img src="fil.png">
</a>
'''
"""
import re
from bs4 import BeautifulSoup
soup = BeautifulSoup(re.sub(r''+[^']+'+', '', data), 'lxml')
for img in soup.find_all(lambda t: t.name == 'img' and not 'alt' in t.attrs):
print(img['src'])
Выход:
fil.png
]++
+ | ... ` , чтобы использовать его необходимо использовать альтернативный пакет регулярных выражений для Python: импорт регулярных выражений как ре