Você pode fornecer alguns exemplos de por que é difícil analisar XML e HTML com uma regex? [fechadas]

402

Um erro que eu vejo as pessoas fazendo mais e mais uma vez está tentando analisar XML ou HTML com um regex. Aqui estão algumas das razões pelas quais a análise de XML e HTML é difícil:

As pessoas querem tratar um arquivo como uma sequência de linhas, mas isso é válido:

<tag
attr="5"
/>

As pessoas querem tratar a tag <ou <como o início de uma tag, mas coisas desse tipo existem na natureza:

<img src="imgtag.gif" alt="<img>" />

As pessoas geralmente desejam corresponder as tags iniciais às tags finais, mas XML e HTML permitem que as tags se contenham (que as expressões regulares tradicionais não conseguem suportar):

<span id="outer"><span id="inner">foo</span></span> 

As pessoas geralmente desejam comparar o conteúdo de um documento (como o famoso problema "encontre todos os números de telefone em uma determinada página"), mas os dados podem ser marcados (mesmo que pareça normal quando visualizados):

<span class="phonenum">(<span class="area code">703</span>)
<span class="prefix">348</span>-<span class="linenum">3020</span></span>

Os comentários podem conter tags mal formatadas ou incompletas:

<a href="foo">foo</a>
<!-- FIXME:
    <a href="
-->
<a href="bar">bar</a>

Que outras dicas você conhece?

Chas. Owens
fonte
14
Os navegadores da Web compreendem esse tipo de confusão milhões de vezes por segundo. Alguém não pode criar uma classe de analisador de páginas da Web para nós, meros mortais?
31909 Jon Winstanley
24
Jon, eles têm. No Perl, existem muitos HTML :: Parser, HTML :: TreeBuilder, etc. Há quase certamente um para o seu idioma.
Chas. Owens
12
A melhor resposta é, stackoverflow.com/a/1732454/135078 (Beware Zalgo)
Kelly S. Francês
3
Há uma boa explicação para por que [você não pode analisar [X] HTML com regex] [1] [1]: stackoverflow.com/a/1732454/468725
Pavel P
4
Aqui está uma boa explicação de como você certamente pode analisar HTML com padrões , e também porque você provavelmente não deseja fazê-lo.
tchrist

Respostas:

260

Aqui está um XML válido e divertido para você:

<!DOCTYPE x [ <!ENTITY y "a]>b"> ]>
<x>
    <a b="&y;>" />
    <![CDATA[[a>b <a>b <a]]>
    <?x <a> <!-- <b> ?> c --> d
</x>

E este pequeno pacote de alegria é HTML válido:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd" [
    <!ENTITY % e "href='hello'">
    <!ENTITY e "<a %e;>">
]>
    <title>x</TITLE>
</head>
    <p id  =  a:b center>
    <span / hello </span>
    &amp<br left>
    <!---- >t<!---> < -->
    &e link </a>
</body>

Sem mencionar toda a análise específica do navegador para construções inválidas.

Boa sorte colocando regex contra isso!

EDIT (Jörg W Mittag): Aqui está outra parte legal do HTML 4.01 bem formado e válido:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
  "http://www.w3.org/TR/html4/strict.dtd"> 
<HTML/
  <HEAD/
    <TITLE/>/
    <P/>
bobince
fonte
6
O XML? Existem algumas construções diferentes lá, o que é problemático? O subconjunto interno de DTD? Isso está definindo uma nova & entidade; chamado 'y', contendo uma sequência ']>' que normalmente, se não estiver entre aspas, terminaria o subconjunto interno.
9990
16
(Isso demonstra que você tem que ter conhecimento bastante profundo sobre alguns dos DTD mais esotérico e arcaica características de XML para analisar um documento corretamente, mesmo se você não é um analisador DTD-validação.)
bobince
17
Os exemplos HTML usam um recurso raramente conhecido: shorttags. Leia mais em w3.org/QA/2007/10/shorttags.html
netvope
25
Toda vez que alguém escreve HTML, como mostrado acima, Tim Berners-Lee derrama uma única lágrima.
fgysin restabelece Monica 15/09
5
Eu amo como o marcador de sintaxe do Stackoverflow falha na 1ª ocorrência de "]".
GlassGhost
71

Na realidade

<img src="imgtag.gif" alt="<img>" />

não é HTML válido e também não é XML válido.

Não é um XML válido porque os '<' e '>' não são caracteres válidos dentro das sequências de atributos. Eles precisam ser escapados usando as entidades XML correspondentes & lt; e & gt;

Também não é HTML válido porque o formulário de fechamento curto não é permitido em HTML (mas está correto em XML e XHTML). A tag 'img' também é uma tag implicitamente fechada, conforme a especificação HTML 4.01. Isso significa que o fechamento manual está realmente errado e é equivalente a fechar qualquer outra tag duas vezes.

A versão correta em HTML é

<img src="imgtag.gif" alt="&lt;img&gt;">

e a versão correta em XHTML e XML é

<img src="imgtag.gif" alt="&lt;img&gt;"/>

O exemplo a seguir que você deu também é inválido

<
tag
attr="5"
/>

Este também não é um HTML ou XML válido. O nome da tag deve estar logo atrás do '<', embora os atributos e o fechamento '>' possam estar onde quiserem. Portanto, o XML válido é realmente

<tag
attr="5"
/>

E aqui está outro mais engraçado: você pode realmente optar por usar "ou" como seu atributo entre aspas

<img src="image.gif" alt='This is single quoted AND valid!'>

Todos os outros motivos postados estão corretos, mas o maior problema com a análise de HTML é que as pessoas geralmente não entendem todas as regras de sintaxe corretamente. O fato de seu navegador interpretar seu grupo de tags como HTML não significa que você realmente escreveu HTML válido.

Edit: E mesmo stackoverflow.com concorda comigo sobre a definição de válido e inválido. Seu XML / HTML inválido não está destacado, enquanto minha versão corrigida é.

Basicamente, o XML não é feito para ser analisado com regexps. Mas também não há razão para fazê-lo. Existem muitos analisadores XML para cada idioma. Você pode escolher entre analisadores SAX, DOM e Pull. É garantido que tudo isso é muito mais rápido que a análise com um regexp e, em seguida, você pode usar tecnologias legais como XPath ou XSLT na árvore DOM resultante.

Minha resposta é, portanto: não apenas é difícil analisar XML com regexps, mas também é uma má idéia. Basta usar um dos milhões de analisadores XML existentes e aproveitar todos os recursos avançados do XML.

HTML é muito difícil de tentar analisar sozinho. Primeiro, a sintaxe legal possui muitas pequenas sutilezas das quais você pode não estar ciente e, em segundo lugar, o HTML em estado selvagem é apenas uma pilha enorme e fedorenta de (você entendeu). Há uma variedade de bibliotecas de analisador lax que fazem um bom trabalho no manuseio de HTML como uma sopa de tags, basta usá-las.

LordOfThePigs
fonte
8
Você não precisa escapar como se fosse.
3128 Joey
8
Ok, s / válido / existe em estado selvagem / g
Chas. Owens
11
Na verdade, de acordo com a especificação, você deve escapar> como> assim como você deve escapar <como <& and & amp; e em atributos "como" e "como" é apenas aquele analisador de muitos #
LordOfThePigs
19
A especificação não diz que '>' deve ser escapado - exceto no caso especial da sequência ']]>' no conteúdo. Por esse motivo, é mais fácil escapar sempre de '>', mas não é exigido pelas especificações.
31909 bobince as
8
>sinal é perfeitamente válido em html stackoverflow.com/questions/94528/…
jfs 28/11/2009
56

Eu escrevi uma entrada de blog inteira sobre este assunto: Limitações da expressão regular

O cerne da questão é que HTML e XML são estruturas recursivas que exigem mecanismos de contagem para analisar adequadamente. Um regex verdadeiro não é capaz de contar. Você deve ter uma gramática livre de contexto para poder contar.

O parágrafo anterior vem com uma pequena ressalva. Certas implementações de regex agora suportam a ideia de recursão. No entanto, uma vez que você começa a adicionar recursão em suas expressões de expressão regular, você está realmente esticando os limites e deve considerar um analisador.

JaredPar
fonte
20

Um problema que não está na sua lista é que os atributos podem aparecer em qualquer ordem; portanto, se o seu regex está procurando um link com o href "foo" e a classe "bar", eles podem vir em qualquer ordem e ter qualquer número de outras opções. coisas entre eles.

AmbroseChapel
fonte
Ah, sim, essa foi mesmo a pergunta que me levou a fazer essa (o primeiro link).
Chas. Owens
16

Depende do que você quer dizer com "análise". De um modo geral, o XML não pode ser analisado usando regex, pois a gramática XML não é de forma alguma regular. Simplificando, as expressões regulares não podem contar (bem, as expressões regulares Perl podem realmente contar as coisas), portanto, você não pode equilibrar as tags de abertura e fechamento.

Anton Gogolev
fonte
eu acho backreferences pode resolver o problema de etiquetas de abrir e fechar
Rishul Matta
11
@RishulMatta: como? Você tem apenas um número limitado de referências anteriores e observe que precisa reverter as tags ... Além disso, a definição estrita de expressões regulares não permite referências posteriores.
Willem Van Onsem
O .NET permite equilibrar expressões, que são acionadas e pressionadas, e teoricamente poderia ser usado para corresponder à hierarquia. Mas ainda é uma má ideia.
Abel
9

As pessoas estão realmente cometendo um erro usando uma regex ou é simplesmente bom o suficiente para a tarefa que estão tentando realizar?

Concordo totalmente que a análise de html e xml usando um regex não é possível, pois outras pessoas responderam.

No entanto, se o seu requisito não é analisar html / xml, mas apenas obter um pequeno pedaço de dados em um bit "bom" conhecido de html / xml, talvez uma expressão regular ou mesmo uma "substring" ainda mais simples seja boa o suficiente.

Robin Day
fonte
7
Defina "bom o suficiente". Inevitavelmente, o regex simples não funcionará. Não está combinando algo ou algo que você não deveria encontrar um bug? Nesse caso, usar expressões regulares é um erro. Analisadores HTML e XML não são difíceis de usar. Evitar aprendê-los é uma economia falsa.
Chas. Owens
11
ok, defina "bom o suficiente". Digamos que eu tenho uma página da Web que informa o endereço IP do cliente. É tudo o que faz. Agora, preciso escrever um aplicativo para a máquina do cliente que me informe seu endereço IP. Vou a esse site, procuro um endereço IP e o devolvo. Não é necessário analisar o HTML!
Robin Day
2
Se você possui uma sequência arbitrária cujo formato está completamente sob seu controle, o fato de a sequência ser um XML bem formado não é relevante. Mas quase nenhum caso de uso para XML realmente se enquadra nessa categoria.
Robert Rossney 31/03/09
15
Posso dizer por experiência dolorosa que na maioria das vezes é possível obter o que você deseja utilizando padrões regex complexos e absurdos. Até que o site sofra uma pequena alteração hilariante e você possa jogar esse regex que fez você chorar por dois dias pela janela e começar de novo.
Thomasz
@ Robert: "quase nenhum caso de uso" é um exagero. Na minha experiência, existem casos de uso comuns o suficiente. YAGNI se aplica aqui ... às vezes. O truque é saber o quanto a sua solução precisa ser à prova de balas e durar para a tarefa específica que você está abordando. Robin tem um bom argumento. Ele está apenas dizendo que a análise XML completa nem sempre vale a pena ... o que é verdade mesmo que você saiba como usá-lo.
LarsH 19/07
6

As pessoas normalmente assumem o padrão de escrever padrões gananciosos, o que geralmente leva a um arquivo * não-pensado, arrastando grandes pedaços de arquivo para o maior <foo>. * </foo> possível.

caos
fonte
2
Além de tornar a repetição preguiçosa .*?<, você pode corrigir isso usando uma classe de caractere negada como [^<]*<. (Disclaimer: obviamente, isso ainda não é infalível, que é o ponto da questão.)
Rory O'Kane
6

Estou tentado a dizer "não reinvente a roda". Exceto que XML é um formato muito, muito complexo. Então, talvez eu deva dizer "não reinvente o síncrotron".

Talvez o clichê correto comece "quando tudo que você tem é um martelo ..." Você sabe como usar expressões regulares; a expressão regular é boa para analisar, então por que se preocupar em aprender uma biblioteca de análise XML?

Porque a análise de XML é difícil . Qualquer esforço que você economize por não precisar aprender a usar uma biblioteca de análise XML será mais do que compensado pela quantidade de trabalho criativo e correção de erros que você precisará fazer. Para seu próprio bem, pesquise no Google "XML Library" e aproveite o trabalho de outra pessoa.

Isaac Rabinovitch
fonte
3
Não é tão complexo quanto o C ++.
Cole Johnson
6
@ Cole "Cole9" Johnson Eu também não usaria REs para analisar C ++.
Isaac Rabinovitch
2
Se o XML for um síncrotron, o C ++ seria o Large Hadron Collider.
Kevin Kostlan 02/02
4

Acredito que este clássico tenha as informações que você está procurando. Você pode encontrar o ponto em um dos comentários aqui:

Eu acho que a falha aqui é que HTML é uma gramática Chomsky Tipo 2 (gramática livre de contexto) e RegEx é uma gramática Chomsky Tipo 3 (expressão regular). Como uma gramática tipo 2 é fundamentalmente mais complexa do que uma gramática tipo 3 - você não pode esperar que isso funcione . Mas muitos tentarão, alguns reivindicarão sucesso e outros encontrarão a falha e o atrapalharão totalmente.

Mais algumas informações da Wikipedia: Hierarquia de Chomsky

Adam Arold
fonte
6
"Expressão regular" não tem exatamente o mesmo significado nas discussões gramaticais formais que aqui. A maioria dos mecanismos regex existentes são mais poderosos que as gramáticas Chomsky Tipo 3 (por exemplo, correspondência não gananciosa, refexs). Alguns mecanismos regex (como o Perl) são completos em Turing. É verdade que mesmo essas são ferramentas ruins para analisar HTML, mas esse argumento frequentemente citado não é o motivo.
dubiousjim
4

Eu acho que os problemas se resumem a:

  1. O regex quase invariavelmente está incorreto. Existem entradas legítimas que não serão correspondidas corretamente. Se você trabalhar duro o suficiente, poderá torná-lo 99% correto, ou 99,999%, mas torná-lo 100% correto é quase impossível, mesmo que apenas por causa das coisas estranhas que o XML permite usando entidades.

  2. Se o regex estiver incorreto, mesmo para 0,00001% das entradas, você terá um problema de segurança, porque alguém poderá descobrir a entrada que interromperá seu aplicativo.

  3. Se o regex estiver correto o suficiente para cobrir 99,99% dos casos, será completamente ilegível e impossível de manter.

  4. É muito provável que um regex tenha um desempenho muito ruim em arquivos de entrada de tamanho moderado. Meu primeiro encontro com XML foi substituir um script Perl que (incorretamente) analisou documentos XML recebidos por um analisador XML adequado, e não apenas substituímos 300 linhas de código ilegível por 100 linhas que qualquer um podia entender, mas melhoramos o tempo de resposta do usuário de 10 segundos a cerca de 0,1 segundos.

Michael Kay
fonte
1

De um modo geral, o XML não pode ser analisado usando regex, pois a gramática XML não é de forma alguma regular. Simplificando, as expressões regulares não podem contar (bem, as expressões regulares Perl podem realmente contar as coisas), portanto, você não pode equilibrar as tags de abertura e fechamento.

Discordo. Se você usar recursivo no regex, poderá encontrar facilmente tags de abrir e fechar.

Aqui eu mostrei exemplo de regex para evitar a análise de erros de exemplos na primeira mensagem.

Maxim Suslov
fonte
Primeiro, expressões regulares recursivas não são expressões regulares (se você olhar entre parênteses, verá que eu admito que as expressões regulares de Perl, que são recursivas, podem contar coisas necessárias para lidar com HTML). Segundo, seu exemplo é para XHTML ou XML que está bem formado. HTML não está bem formado. Terceiro, você deve se perguntar: é mais fácil estender e manter um analisador escrito em uma linguagem regex recursiva ou em uma linguagem de programação de uso geral.
Chas. Owens
Quarto, até o seu exemplo é trivialmente quebrado enquanto ainda é um XML válido. Adicione um espaço entre content_block e id e ele falhará. Estou certo de que, se eu passasse mais alguns minutos, encontraria algum outro erro estrutural no seu código. Simplesmente não é uma boa ideia.
Chas. Owens
1

Dei uma resposta simplificada para esse problema aqui . Embora ela não represente a marca de 100%, explico como é possível se você estiver disposto a fazer algum trabalho de pré-processamento.

Erutan409
fonte