Jak więc działa parser HTML? Czy nie używa wyrażeń regularnych do analizowania?
Więc nie.
Jeśli wrócisz w swoim mózgu do teorii kursu obliczeniowego, jeśli wziąłeś udział w kursie kompilatorów lub czymś podobnym, możesz przypomnieć sobie, że istnieją różne rodzaje języków i modeli obliczeniowych. Nie mam kwalifikacji, by wchodzić we wszystkie szczegóły, ale mogę omówić z tobą kilka głównych punktów.
Najprostszym rodzajem języka i obliczeń (do tych celów) jest język zwykły. Można je generować za pomocą wyrażeń regularnych i rozpoznawać za pomocą automatów skończonych. Zasadniczo oznacza to, że „analizowanie” łańcuchów w tych językach używa stanu, ale nie pamięci pomocniczej. HTML z pewnością nie jest zwykłym językiem. Jeśli się nad tym zastanowić, lista tagów może być dowolnie zagnieżdżona głęboko. Na przykład tabele mogą zawierać tabele, a każda tabela może zawierać wiele zagnieżdżonych tagów. W przypadku wyrażeń regularnych możesz wybrać parę tagów, ale z pewnością nie będzie to dowolne zagnieżdżenie.
Klasyczny prosty język, który nie jest regularny, jest poprawnie dopasowany do nawiasów. Mimo prób, nigdy nie będziesz w stanie zbudować wyrażenia regularnego (lub automatu skończonego), które zawsze będzie działać. Potrzebujesz pamięci do śledzenia głębokości zagnieżdżenia.
Maszyna stanów ze stosem pamięci to kolejna siła modelu obliczeniowego. Nazywa się to automatem przesuwającym w dół i rozpoznaje języki generowane przez gramatykę bezkontekstową. W tym miejscu możemy rozpoznać poprawnie dopasowane nawiasy - rzeczywiście, stos jest dla niego idealnym modelem pamięci.
Czy to wystarczy dla HTML? Niestety nie. Może dla super-dupera, właściwie sprawdzonego XML-a, w którym wszystkie tagi zawsze są idealnie dopasowane. W prawdziwym HTML możesz łatwo znaleźć fragmenty, takie jak <b><i>wow!</b></i>
. To oczywiście nie zagnieździ się, więc aby go przeanalizować poprawnie, stos nie jest wystarczająco silny.
Następnym poziomem obliczeń są języki generowane przez gramatykę ogólną i rozpoznawane przez maszyny Turinga. Ogólnie przyjmuje się, że jest to faktycznie najsilniejszy dostępny model obliczeniowy - maszyna stanu z pamięcią pomocniczą, której pamięć można modyfikować w dowolnym miejscu. To właśnie potrafią języki programowania. To jest poziom złożoności, na którym żyje HTML.
Podsumowując wszystko w jednym zdaniu: aby przeanalizować ogólny HTML, potrzebujesz prawdziwego języka programowania, a nie wyrażenia regularnego.
HTML jest parsowany w taki sam sposób, jak inne języki: leksowanie i parsowanie. Etap leksowania dzieli strumień pojedynczych znaków na znaczące tokeny. Etap analizy składa tokeny, używając stanów i pamięci, w logicznie spójny dokument, na którym można działać.