Regex seleciona todo o texto entre as tags


143

Qual é a melhor maneira de selecionar todo o texto entre duas tags - ex: o texto entre todas as tags 'pré' na página.


2
A melhor maneira é usar um html-parser como "Beautiful Soup" se você estiver em python ...
Fredrik Pihl

1
A melhor maneira é usar o analisador XML / HTML.
Daniel O'Hara

4
Em geral, o uso de expressões regulares para analisar HTML não é uma boa idéia: stackoverflow.com/questions/1732348/...
murgatroid99

Não analise o texto entre as tags com regex, pois as tags aninhadas arbitrariamente tornam o HTML não regular. As tags correspondentes parecem estar bem. /<div>.*?<\/div>/.exec("<div><div></div></div>")
precisa saber é

Respostas:


157

Você pode usar "<pre>(.*?)</pre>"(substituindo pre pelo texto que desejar) e extrair o primeiro grupo (para instruções mais específicas, especificar um idioma), mas isso pressupõe a noção simplista de que você tem HTML muito simples e válido.

Como outros comentaristas sugeriram, se você estiver fazendo algo complexo, use um analisador de HTML.


41
Isso não seleciona o texto entre as tags, inclui as tags.
capikaw

3
Você precisa fazer a seleção usando ()
Sahu V Kumar

2
Para multi marcas de linha: <html_tag> ((\ s) + (+).) + <\ / Html_tag> (+.)
Felipe Augusto

Isso ainda tem visibilidade, então: se você ainda vê as <pre>tags depois de tentar <pre>(.*?)<\/pre>, é porque está vendo o que é capturado pela correspondência completa em vez do grupo de captura (. *?). Parece extravagante, mas eu sempre penso "parênteses = par de ladrões" porque, a menos que (seja seguido por um ?como em (?:ou (?>, cada partida terá duas capturas: 1 para a partida completa e 1 para o grupo de captura. Cada conjunto adicional de parênteses adiciona uma captura adicional. Você só precisa saber como recuperar as duas capturas no idioma em que estiver trabalhando.
Rbsdca

137

A tag pode ser concluída em outra linha. É por isso que \nprecisa ser adicionado.

<PRE>(.|\n)*?<\/PRE>

5
Ponto importante sobre a adição (.|\n)*?ao lidar com tags HTML em várias linhas. A resposta selecionada funciona apenas se as tags HTML estiverem na mesma linha.
Caleuanhopkins

3
<PRE> (. | \ N | \ r \ n) *? <\ / PRE> para terminações de linha do Windows
Marque

3
Nunca use (.|\n)*?para combinar com qualquer caractere. Sempre use .com o smodificador (linha única). Ou uma [\s\S]*?solução alternativa.
precisa saber é o seguinte

Eu queria selecionar comentários de código no bloco de notas ++, então, usando esta resposta, vim com o /\*(.|\n)*?\*/que fez o trabalho - obrigado
wkille 27/02

resposta perfeita muito obrigado
Omda 18/06

25

Isto é o que eu usaria.

(?<=(<pre>))(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|`~]| )+?(?=(</pre>))

Basicamente, o que faz é:

(?<=(<pre>))A seleção deve ser precedida por uma <pre>tag

(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|~]| )Esta é apenas uma expressão regular que quero aplicar. Nesse caso, ele seleciona caracteres de letra ou dígito ou nova linha ou alguns caracteres especiais listados no exemplo entre colchetes. O caractere de pipe |significa simplesmente " OU ".

+?Os estados de caracteres positivos para selecionar uma ou mais das ordens acima não importam. O ponto de interrogação altera o comportamento padrão de 'ganancioso' para 'ingrato'.

(?=(</pre>))A seleção deve ser anexada pela </pre>tag

insira a descrição da imagem aqui

Dependendo do seu caso de uso, pode ser necessário adicionar alguns modificadores como ( i ou m )

  • i - não diferencia maiúsculas de minúsculas
  • m - pesquisa multilinhas

Aqui eu realizei essa pesquisa no Sublime Text para não precisar usar modificadores no meu regex.

Javascript não suporta lookbehind

O exemplo acima deve funcionar bem com linguagens como PHP, Perl, Java ... No entanto, o Javascript não suporta lookbehind, portanto, precisamos esquecer o uso (?<=(<pre>))e procurar algum tipo de solução alternativa. Talvez simples tira os quatro primeiros caracteres do nosso resultado para cada seleção, como aqui Regex corresponde ao texto entre as tags

Também olhar para o DOCUMENTAÇÃO JavaScript REGEX para parênteses não captura


Observe que você precisa escapar dos caracteres de aspas simples / duplas com `para colocar o regexp em uma string.
David Zwart 14/09

18

use o padrão abaixo para obter conteúdo entre os elementos. Substitua [tag]pelo elemento real do qual você deseja extrair o conteúdo.

<[tag]>(.+?)</[tag]>

Em algum momento, as tags terão atributos, como anchortag href, e então use o padrão abaixo.

 <[tag][^>]*>(.+?)</[tag]>

Tente o primeiro exemplo como '<head> (. +?) </head>' e funcione como o esperado. Mas não tenho resultados com o segundo.
21816 Alex Byrth

1
isso não funciona. <[tag]>irá corresponder <t>, <a>e<g>
Martin Schneider

2
@ MA-Maddin - Eu acho que você perdeu a Replace [tag] with the actual element you wish to extract the content fromparte.
LWC

2
Oh bem, sim. Estes []deveriam ter sido omitidos por completo. Isso seria mais clara, por causa de seu significado em RegEx eo fato de que as pessoas digitalizar o código primeiro e ler o texto depois;)
Martin Schneider

14

Para excluir as tags de delimitação:

(?<=<pre>)(.*?)(?=</pre>)

(?<=<pre>) procura texto depois <pre>

(?=</pre>) procura texto antes </pre>

Os resultados serão inseridos na pretag


As pessoas que usam este olhar para resposta @krishna de Thakor que também pode considerar se o conteúdo tem nova linha entre as tags
KingKongCoder

Isso ajudou no meu caso (sem precisar considerar novas linhas). Obrigado.
Pking

6

Você não deve tentar analisar html com expressões regulares, veja esta pergunta e como ela acabou.

Nos termos mais simples, o html não é uma linguagem comum, portanto você não pode analisar totalmente com expressões regulares.

Dito isto, você pode analisar subconjuntos de html quando não houver tags semelhantes aninhadas. Portanto, desde que algo entre e não seja essa tag em si, isso funcionará:

preg_match("/<([\w]+)[^>]*>(.*?)<\/\1>/", $subject, $matches);
$matches = array ( [0] => full matched string [1] => tag name [2] => tag content )

Uma idéia melhor é usar um analisador, como o DOMDocument nativo, para carregar seu html, selecione sua tag e obtenha o html interno que pode ser algo como isto:

$obj = new DOMDocument();
$obj -> load($html);
$obj -> getElementByTagName('el');
$value = $obj -> nodeValue();

E como esse é um analisador adequado, ele poderá manipular tags de aninhamento etc.


2
Só quero dizer que estou um pouco perturbado que isso ainda esteja acumulando votos negativos, enquanto é a única resposta que fornece uma solução adequada ao lado da regex e também adicionei um amplo aviso de que provavelmente não é o caminho certo ... Pelo menos comente o que há de errado com a minha resposta, por favor.
sg3s

1
A pergunta não foi marcada com php. Não sei como PHP entrou em cena ...
trincot

@ Trincot Isso foi há mais de 7 anos atrás, então não me lembro. De qualquer forma, é um exemplo de solução do problema com uma regex e com um analisador. O regex é bom e php é exatamente o que eu sabia bem na época.
sg3s 27/01/19

Entendo, vi seu primeiro comentário e achei que isso poderia explicar alguns dos votos negativos.
precisa saber é


4

Esta parece ser a expressão regular mais simples de tudo o que encontrei

(?:<TAG>)([\s\S]*)(?:<\/TAG>)
  1. Excluir etiqueta de abertura (?:<TAG>) das correspondências
  2. Incluir caracteres em branco ou não em branco ([\s\S]*) em nas correspondências
  3. Excluir marca de fechamento (?:<\/TAG>)das correspondências

3

Esta resposta supõe suporte para olhar ao redor! Isso me permitiu identificar todo o texto entre pares de tags de abertura e fechamento. Esse é todo o texto entre o '>' e o '<'. Funciona porque olhar ao redor não consome os caracteres correspondentes.

(? <=>) ([\ w \ s] +) (? = </)

Eu testei em https://regex101.com/ usando este fragmento HTML.

<table>
<tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td></tr>
<tr><td>Cell 4</td><td>Cell 5</td><td>Cell 6</td></tr>
</table>

É um jogo de três partes: o olhar para trás, o conteúdo e o futuro.

(?<=>)    # look behind (but don't consume/capture) for a '>'
([\w\s]+) # capture/consume any combination of alpha/numeric/whitespace
(?=<\/)   # look ahead  (but don't consume/capture) for a '</'

captura de tela de regex101.com

Espero que sirva como ponto de partida para 10. Sorte.


Obrigado. Não é apenas uma resposta melhor, mas também um ótimo link para o site regex101. Voto a favor! 🙂
Sean Feldman

2

var str = "Lorem ipsum <pre>text 1</pre> Lorem ipsum <pre>text 2</pre>";
    str.replace(/<pre>(.*?)<\/pre>/g, function(match, g1) { console.log(g1); });

Como a resposta aceita é sem código javascript, adicione isso:


1

preg_match_all(/<pre>([^>]*?)<\/pre>/,$content,$matches)esse regex selecionará tudo entre a tag. não importa se está em nova linha (trabalhe com várias linhas.


1

No Python, definir o DOTALLsinalizador capturará tudo, incluindo novas linhas.

Se o sinalizador DOTALL tiver sido especificado, ele corresponderá a qualquer caractere, incluindo uma nova linha. docs.python.org

#example.py using Python 3.7.4  
import re

str="""Everything is awesome! <pre>Hello,
World!
    </pre>
"""

# Normally (.*) will not capture newlines, but here re.DOTATLL is set 
pattern = re.compile(r"<pre>(.*)</pre>",re.DOTALL)
matches = pattern.search(str)

print(matches.group(1))

python example.py

Hello,
World!

Capturando texto entre todas as marcas de abertura e fechamento em um documento

Capturar texto entre todas as tags de abertura e fechamento de um documento finditeré útil. No exemplo abaixo, três <pre>tags de abertura e fechamento estão presentes na string.

#example2.py using Python 3.7.4
import re

# str contains three <pre>...</pre> tags
str = """In two different ex-
periments, the authors had subjects chat and solve the <pre>Desert Survival Problem</pre> with a
humorous or non-humorous computer. In both experiments the computer made pre-
programmed comments, but in study 1 subjects were led to believe they were interact-
ing with another person. In the <pre>humor conditions</pre> subjects received a number of funny
comments, for instance: “The mirror is probably too small to be used as a signaling
device to alert rescue teams to your location. Rank it lower. (On the other hand, it
offers <pre>endless opportunity for self-reflection</pre>)”."""

# Normally (.*) will not capture newlines, but here re.DOTATLL is set
# The question mark in (.*?) indicates non greedy matching.
pattern = re.compile(r"<pre>(.*?)</pre>",re.DOTALL)

matches = pattern.finditer(str)


for i,match in enumerate(matches):
    print(f"tag {i}: ",match.group(1))

python example2.py

tag 0:  Desert Survival Problem
tag 1:  humor conditions
tag 2:  endless opportunity for self-reflection

0

Para várias linhas:

<htmltag>(.+)((\s)+(.+))+</htmltag>


0

Eu uso esta solução:

preg_match_all( '/<((?!<)(.|\n))*?\>/si',  $content, $new);
var_dump($new);

-1

Em Javascript (entre outros), isso é simples. Abrange atributos e várias linhas:

/<pre[^>]*>([\s\S]*?)<\/pre>/

-4
<pre>([\r\n\s]*(?!<\w+.*[\/]*>).*[\r\n\s]*|\s*[\r\n\s]*)<code\s+(?:class="(\w+|\w+\s*.+)")>(((?!<\/code>)[\s\S])*)<\/code>[\r\n\s]*((?!<\w+.*[\/]*>).*|\s*)[\r\n\s]*<\/pre>

6
Por favor, apresente / explique sua resposta usando palavras.
Andrew Regan
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.