Allora come funziona un parser HTML? Non usa espressioni regolari per analizzare?
Beh no.
Se torni nel tuo cervello a un corso di teoria del calcolo, se ne hai seguito uno, o un corso per compilatori, o qualcosa di simile, potresti ricordare che ci sono diversi tipi di linguaggi e modelli computazionali. Non sono qualificato per entrare in tutti i dettagli, ma posso rivedere alcuni dei punti principali con te.
Il tipo più semplice di linguaggio e calcolo (per questi scopi) è un linguaggio normale. Questi possono essere generati con espressioni regolari e riconosciuti con automi finiti. Fondamentalmente, ciò significa che le stringhe di "analisi" in questi linguaggi utilizzano lo stato, ma non la memoria ausiliaria. L'HTML non è certamente un linguaggio normale. Se ci pensi, l'elenco dei tag può essere annidato arbitrariamente in profondità. Ad esempio, le tabelle possono contenere tabelle e ogni tabella può contenere molti tag nidificati. Con le espressioni regolari, potresti essere in grado di scegliere un paio di tag, ma certamente non qualcosa di nidificato arbitrariamente.
Un linguaggio semplice classico che non è regolare è rappresentato correttamente dalle parentesi. Per quanto provi, non sarai mai in grado di costruire un'espressione regolare (o un automa finito) che funzionerà sempre. È necessaria la memoria per tenere traccia della profondità di annidamento.
Una macchina a stati con uno stack per la memoria è il prossimo punto di forza del modello computazionale. Questo è chiamato automa push-down e riconosce i linguaggi generati da grammatiche prive di contesto. Qui, possiamo riconoscere le parentesi abbinate correttamente: in effetti, uno stack è il modello di memoria perfetto per questo.
Bene, questo è abbastanza buono per HTML? Purtroppo no. Forse per super-duper XML accuratamente convalidato, in realtà, in cui tutti i tag si allineano sempre perfettamente. Nell'HTML del mondo reale, puoi facilmente trovare snippet come <b><i>wow!</b></i>
. Questo ovviamente non si annida, quindi per analizzarlo correttamente, uno stack non è abbastanza potente.
Il livello successivo di calcolo sono i linguaggi generati da grammatiche generali e riconosciuti dalle macchine di Turing. Questo è generalmente accettato come effettivamente il modello computazionale più potente che esista: una macchina a stati, con memoria ausiliaria, la cui memoria può essere modificata ovunque. Questo è ciò che possono fare i linguaggi di programmazione. Questo è il livello di complessità in cui vive l'HTML.
Per riassumere tutto qui in una frase: per analizzare l'HTML generale, è necessario un vero linguaggio di programmazione, non un'espressione regolare.
L'HTML viene analizzato nello stesso modo in cui vengono analizzati gli altri linguaggi: lexing e parsing. Il passaggio di lexing suddivide il flusso dei singoli personaggi in gettoni significativi. La fase di analisi assembla i token, utilizzando stati e memoria, in un documento logicamente coerente su cui è possibile agire.