Я погоджуюся, що правильний інструмент для розбору XML і, особливо, HTML, є синтаксичним аналізатором, а не механізмом регулярного вираження. Однак, як зазначали інші, іноді використовувати регулярний вираз - це швидше, простіше і виконує роботу, якщо ви знаєте формат даних.
Microsoft насправді має розділ найкращих практик регулярних виразів у .NET Framework і конкретно розповідає про розгляд джерела вводу .
Регулярні вирази мають обмеження, але чи Ви врахували таке?
Рамка .NET унікальна, коли мова йде про регулярні вирази тим, що вона підтримує визначення балансуючої групи .
З цієї причини я вважаю, що ви МОЖЕТЕ розбирати XML, використовуючи регулярні вирази. Зауважте, що він повинен бути дійсним XML ( браузери дуже прощають HTML і дозволяють поганий синтаксис XML всередині HTML ). Це можливо, оскільки "Визначення групи балансування" дозволить механізму регулярного вираження діяти як КПК.
Цитата з цитованої вище статті 1:
.NET двигун регулярних виразів
Як описано вище, правильно врівноважені конструкції не можуть бути описані регулярним виразом. Однак двигун регулярних виразів .NET пропонує кілька конструкцій, які дозволяють розпізнати врівноважені конструкції.
(?<group>)
- висуває захоплений результат на стек захоплення з групою імен.
(?<-group>)
- вискакує найпопулярніший знімок із групою імен поза стеком захоплення.
(?(group)yes|no)
- відповідає частині так, якщо існує група з групою імен, інакше не відповідає жодній частині.
Ці конструкції дозволяють регулярному вираженню .NET імітувати обмежений КПК, по суті дозволяючи прості версії операцій стеку: push, pop та порожні. Прості операції в значній мірі еквівалентні приросту, зменшенню і порівняно з нулем відповідно. Це дозволяє механізму регулярних виразів .NET розпізнавати підмножину безконтекстних мов, зокрема тих, для яких потрібен лише простий лічильник. Це в свою чергу дозволяє нетрадиційним регулярним виразам .NET розпізнавати окремі правильно збалансовані конструкції.
Розглянемо наступний регулярний вираз:
(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
<!-- .*? --> |
<[^>]*/> |
(?<opentag><(?!/)[^>]*[^/]>) |
(?<-opentag></[^>]*[^/]>) |
[^<>]*
)*
(?(opentag)(?!))
Використовуйте прапори:
- Однолінійний
- IgnorePatternWhitespace (не потрібно, якщо ви згортаєте регулярний вираз і видаляєте всі пробіли)
- IgnoreCase (не потрібно)
Пояснений регулярний вираз (вбудований)
(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?> # atomic group / don't backtrack (faster)
<!-- .*? --> | # match xml / html comment
<[^>]*/> | # self closing tag
(?<opentag><(?!/)[^>]*[^/]>) | # push opening xml tag
(?<-opentag></[^>]*[^/]>) | # pop closing xml tag
[^<>]* # something between tags
)* # match as many xml tags as possible
(?(opentag)(?!)) # ensure no 'opentag' groups are on stack
Ви можете спробувати це у кращому. NET регулярному тестері вираження .
Я використовував зразок джерела:
<html>
<body>
<div>
<br />
<ul id="matchMe" type="square">
<li>stuff...</li>
<li>more stuff</li>
<li>
<div>
<span>still more</span>
<ul>
<li>Another >ul<, oh my!</li>
<li>...</li>
</ul>
</div>
</li>
</ul>
</div>
</body>
</html>
Це виявило збіг:
<ul id="matchMe" type="square">
<li>stuff...</li>
<li>more stuff</li>
<li>
<div>
<span>still more</span>
<ul>
<li>Another >ul<, oh my!</li>
<li>...</li>
</ul>
</div>
</li>
</ul>
хоча насправді вийшло так:
<ul id="matchMe" type="square"> <li>stuff...</li> <li>more stuff</li> <li> <div> <span>still more</span> <ul> <li>Another >ul<, oh my!</li> <li>...</li> </ul> </div> </li> </ul>
Нарешті, мені дуже сподобалась стаття Джеффа Етвуда: Розбір Html The Cthulhu Way . Досить смішно, він наводить відповідь на це запитання, що наразі має понад 4 кб голосів.