Então, como funciona um analisador de HTML? Não usa expressões regulares para analisar?
Bem não.
Se você voltar em seu cérebro para um curso de teoria da computação, se você fez um, ou um curso de compiladores, ou algo semelhante, você deve se lembrar que existem diferentes tipos de linguagens e modelos computacionais. Não estou qualificado para entrar em todos os detalhes, mas posso revisar alguns dos pontos principais com você.
O tipo mais simples de linguagem e computação (para esses propósitos) é uma linguagem regular. Eles podem ser gerados com expressões regulares e reconhecidos com autômatos finitos. Basicamente, isso significa que as strings de "análise" nessas linguagens usam estado, mas não memória auxiliar. HTML certamente não é uma linguagem regular. Se você pensar sobre isso, a lista de tags pode ser aninhada profundamente de forma arbitrária. Por exemplo, as tabelas podem conter tabelas e cada tabela pode conter muitas tags aninhadas. Com as expressões regulares, você pode escolher um par de tags, mas certamente nada aninhado arbitrariamente.
Uma linguagem simples clássica que não é regular é a combinação correta de parênteses. Por mais que tente, você nunca será capaz de construir uma expressão regular (ou autômato finito) que sempre funcionará. Você precisa de memória para controlar a profundidade do aninhamento.
Uma máquina de estado com uma pilha de memória é a próxima força do modelo computacional. Isso é chamado de autômato push-down e reconhece linguagens geradas por gramáticas livres de contexto. Aqui, podemos reconhecer parênteses combinados corretamente - de fato, uma pilha é o modelo de memória perfeito para ela.
Bem, isso é bom o suficiente para HTML? Infelizmente não. Talvez para um XML super-duper cuidadosamente validado, na verdade, no qual todas as tags sempre se alinham perfeitamente. Em HTML no mundo real, você pode facilmente encontrar trechos como <b><i>wow!</b></i>
. Isso obviamente não aninha, então, para analisá-lo corretamente, uma pilha não é poderosa o suficiente.
O próximo nível de computação são as linguagens geradas por gramáticas gerais e reconhecidas pelas máquinas de Turing. É geralmente aceito como efetivamente o modelo computacional mais forte que existe - uma máquina de estado, com memória auxiliar, cuja memória pode ser modificada em qualquer lugar. Isso é o que as linguagens de programação podem fazer. Este é o nível de complexidade em que reside o HTML.
Para resumir tudo aqui em uma frase: para analisar HTML geral, você precisa de uma linguagem de programação real, não uma expressão regular.
O HTML é analisado da mesma forma que outras linguagens: lexing e parsing. A etapa lexing divide o fluxo de caracteres individuais em tokens significativos. A etapa de análise reúne os tokens, usando estados e memória, em um documento logicamente coerente que pode ser executado.