Zgadzam się, że właściwe narzędzie do analizy XML, a zwłaszcza HTML to analizator składni, a nie silnik wyrażeń regularnych. Jednak, jak zauważyli inni, czasem użycie wyrażenia regularnego jest szybsze, łatwiejsze i wykonuje zadanie, jeśli znasz format danych.
Microsoft faktycznie ma sekcję Najlepszych praktyk dotyczących wyrażeń regularnych w .NET Framework, a konkretnie mówi o rozważaniu źródła wejściowego .
Wyrażenia regularne mają ograniczenia, ale czy bierzesz pod uwagę następujące kwestie?
.NET Framework jest wyjątkowy, jeśli chodzi o wyrażenia regularne, ponieważ obsługuje definicje grup równoważących .
Z tego powodu uważam, że MOŻESZ parsować XML przy użyciu wyrażeń regularnych. Zauważ jednak, że musi to być poprawny XML ( przeglądarki bardzo wybaczają HTML i pozwalają na złą składnię XML wewnątrz HTML ). Jest to możliwe, ponieważ „definicja grupy równoważącej” pozwoli silnikowi wyrażeń regularnych działać jako PDA.
Cytat z artykułu 1 cytowanego powyżej:
Silnik wyrażeń regularnych .NET
Jak opisano powyżej, właściwie zrównoważone konstrukty nie mogą być opisane wyrażeniem regularnym. Jednak silnik wyrażeń regularnych .NET udostępnia kilka konstrukcji, które umożliwiają rozpoznanie konstrukcji zrównoważonych.
(?<group>)
- wypycha przechwycony wynik na stosie przechwytywania z grupą nazw.
(?<-group>)
- wyskakuje najwyżej przechwytywanie z grupą nazw ze stosu przechwytywania.
(?(group)yes|no)
- dopasowuje część tak, jeśli istnieje grupa z nazwą grupy, w przeciwnym razie nie pasuje do żadnej części.
Te konstrukcje pozwalają wyrażeniu regularnemu .NET emulować ograniczony PDA, zasadniczo umożliwiając proste wersje operacji na stosie: push, pop i empty. Proste operacje są w zasadzie równoważne odpowiednio inkrementacji, dekrementacji i porównanie do zera. Pozwala to silnikowi wyrażeń regularnych .NET rozpoznawać podzbiór języków bezkontekstowych, w szczególności tych, które wymagają jedynie prostego licznika. To z kolei pozwala nietradycyjnym wyrażeniom regularnym .NET rozpoznawać poszczególne odpowiednio zrównoważone konstrukcje.
Rozważ następujące wyrażenie regularne:
(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
<!-- .*? --> |
<[^>]*/> |
(?<opentag><(?!/)[^>]*[^/]>) |
(?<-opentag></[^>]*[^/]>) |
[^<>]*
)*
(?(opentag)(?!))
Użyj flag:
- Pojedyncza linia
- IgnorePatternWhitespace (nie jest konieczne, jeśli zwiniesz wyrażenie regularne i usuniesz wszystkie białe znaki)
- IgnoreCase (niepotrzebne)
Wyjaśnienie wyrażeń regularnych (wbudowane)
(?=<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
Możesz tego spróbować w A Better .NET Regular Expression Tester .
Użyłem przykładowego źródła:
<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>
Znaleziono dopasowanie:
<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>
chociaż tak naprawdę wyszło tak:
<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>
Wreszcie, naprawdę podobał mi się artykuł Jeffa Atwooda: Parsing Html The Cthulhu Way . Zabawne, że przytacza odpowiedź na to pytanie, które obecnie ma ponad 4 tys. Głosów.