Regex selecciona todo el texto entre etiquetas


143

¿Cuál es la mejor manera de seleccionar todo el texto entre 2 etiquetas? Por ejemplo: el texto entre todas las etiquetas 'pre' de la página.


2
La mejor manera es usar un analizador html como "Beautiful Soup" si te gusta Python ...
Fredrik Pihl

1
La mejor manera es usar un analizador XML / HTML.
Daniel O'Hara el

44
En general, usar expresiones regulares para analizar html no es una buena idea: stackoverflow.com/questions/1732348/…
murgatroid99

No analice el texto entre etiquetas con expresiones regulares porque las etiquetas anidadas arbitrariamente hacen que HTML no sea regular. Las etiquetas coincidentes parecen estar bien. /<div>.*?<\/div>/.exec("<div><div></div></div>")
jdh8

Respuestas:


157

Puede usar "<pre>(.*?)</pre>", (reemplazando pre por el texto que desee) y extraer el primer grupo (para obtener instrucciones más específicas, especifique un idioma), pero esto supone la noción simplista de que tiene HTML muy simple y válido.

Como han sugerido otros comentaristas, si está haciendo algo complejo, use un analizador HTML.


41
Esto no selecciona el texto entre las etiquetas, incluye las etiquetas.
capikaw 01 de

3
Necesitas tomar la selección usando ()
Sahu V Kumar

2
Para etiquetas de varias líneas: <html_tag> (. +) ((\ S) + (. +)) + <\ / Html_tag>
Felipe Augusto

Esto todavía tiene visibilidad, por lo tanto: si aún ve <pre>etiquetas después de intentarlo <pre>(.*?)<\/pre>, es porque está mirando lo que captura la coincidencia completa en lugar del grupo de captura (. *?). Suena cursi pero siempre pienso "paréntesis = par de ladrones" porque a menos que (sea ​​seguido por un ?como en (?:o (?>, cada partida tendrá dos capturas: 1 para la partida completa y 1 para el grupo de captura. Cada conjunto adicional de paréntesis agrega una captura adicional. Solo tiene que saber cómo recuperar ambas capturas en cualquier idioma con el que esté trabajando.
rbsdca

137

La etiqueta se puede completar en otra línea. Por eso es \nnecesario agregarlo.

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

55
Punto importante sobre la adición (.|\n)*?cuando se trata con etiquetas HTML en varias líneas. La respuesta seleccionada solo funciona si las etiquetas HTML están en la misma línea.
Caleuanhopkins

3
<PRE> (. | \ N | \ r \ n) *? <\ / PRE> para terminaciones de línea de Windows
Marque el

3
Nunca lo use (.|\n)*?para que coincida con ningún carácter. Utilice siempre .con el smodificador (una línea). O una [\s\S]*?solución alternativa.
Wiktor Stribiżew

Quería seleccionar comentarios de código en notepad ++, así que usando esta respuesta se me ocurrió /\*(.|\n)*?\*/que hizo el trabajo - gracias
wkille

respuesta perfecta muchas gracias
Omda

25

Esto es lo que usaría.

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

Básicamente lo que hace es:

(?<=(<pre>))La selección tiene que anteponerse con la <pre>etiqueta

(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|~]| )Esta es solo una expresión regular que quiero aplicar. En este caso, selecciona letra o dígito o carácter de nueva línea o algunos caracteres especiales enumerados en el ejemplo entre corchetes. El carácter de la tubería |simplemente significa " O ".

+?Además de los estados de caracteres para seleccionar uno o más de los anteriores, el orden no importa. El signo de interrogación cambia el comportamiento predeterminado de "codicioso" a "no codicioso".

(?=(</pre>))La selección debe ser agregada por la </pre>etiqueta

ingrese la descripción de la imagen aquí

Dependiendo de su caso de uso puede que tenga que añadir algunos modificadores como ( i o m )

  • i - no distingue entre mayúsculas y minúsculas
  • m - búsqueda multilínea

Aquí realicé esta búsqueda en Sublime Text para no tener que usar modificadores en mi expresión regular.

Javascript no es compatible con mirar atrás

El ejemplo anterior debería funcionar bien con lenguajes como PHP, Perl, Java ... Javascript, sin embargo, no admite mirar hacia atrás, por lo que debemos olvidarnos de usar (?<=(<pre>))y buscar algún tipo de solución alternativa. Tal vez simplemente elimine los primeros cuatro caracteres de nuestro resultado para cada selección, como aquí Texto de coincidencia de expresiones regulares entre etiquetas

También mire la DOCUMENTACIÓN JAVASCRIPT REGEX para paréntesis sin captura


Tenga en cuenta que debe escapar de los caracteres de comillas simples / dobles con `para poner la expresión regular en una cadena.
David Zwart

18

use el siguiente patrón para obtener contenido entre elementos. Reemplace [tag]con el elemento real del que desea extraer el contenido.

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

Algunas veces las etiquetas tendrán atributos, como anchortener etiquetas href, luego use el patrón a continuación.

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

Pruebe el primer ejemplo como '<head> (. +?) </head>' y funciona como se esperaba. Pero no tengo resultados con el segundo.
Alex Byrth

1
Esto no funciona. <[tag]>coincidirá <t>, <a>y<g>
Martin Schneider

2
@ MA-Maddin - Creo que te perdiste el Replace [tag] with the actual element you wish to extract the content frompapel.
LWC

2
Oh bueno, si. Estos []deberían haberse omitido por completo. Eso sería más claro, debido a su significado en RegEx y al hecho, que las personas escanean el código primero y leen el texto después;)
Martin Schneider

14

Para excluir las etiquetas delimitadoras:

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

(?<=<pre>) busca texto después <pre>

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

Los resultados enviarán un mensaje de texto dentro de la preetiqueta


Las personas que usan este vistazo a la respuesta de @krishna thakor que también puede considerar si el contenido tiene una nueva línea entre las etiquetas
KingKongCoder

Esto ayudó en mi caso (no es necesario considerar nuevas líneas). Gracias.
Pking

6

No debería intentar analizar html con expresiones regulares, vea esta pregunta y cómo resultó.

En los términos más simples, html no es un lenguaje regular, por lo que no se puede analizar completamente con expresiones regulares.

Dicho esto, puede analizar subconjuntos de html cuando no hay etiquetas similares anidadas. Entonces, siempre que algo entre y no sea esa etiqueta en sí, esto funcionará:

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

Una mejor idea es usar un analizador, como el DOMDocument nativo, para cargar su html, luego seleccione su etiqueta y obtenga el html interno que podría verse así:

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

Y dado que este es un analizador adecuado, podrá manejar etiquetas de anidamiento, etc.


2
Solo quiero decir que estoy un poco molesto porque esto todavía está acumulando votos negativos, mientras que es la única respuesta que proporciona una solución adecuada junto a la expresión regular y también agregué una amplia advertencia de que probablemente no sea la forma correcta ... Al menos comente lo que está mal en mi respuesta, por favor.
sg3s

1
La pregunta no fue etiquetada con php. No estoy seguro de cómo PHP entró en escena ...
trincot

@trincot Esto fue hace más de 7 años, por lo que no puedo recordar. En cualquier caso, es un ejemplo de resolución del problema con una expresión regular y con un analizador sintáctico. La expresión regular es buena y php es justo lo que conocía bien en ese momento.
sg3s

Entiendo, vi su primer comentario y pensé que esto podría explicar algunos de los votos negativos.
Trincot

5

Prueba esto....

(?<=\<any_tag\>)(\s*.*\s*)(?=\<\/any_tag\>)

3
Tenga en cuenta que mirar hacia atrás no es compatible con JavaScript.
allicarn

Ooo por supuesto, pero esta expresión regular es para Java. gracias por tu nota
Heriberto Rivera

4

Esta parece ser la expresión regular más simple de todo lo que encontré

(?:<TAG>)([\s\S]*)(?:<\/TAG>)
  1. Excluir etiqueta de apertura (?:<TAG>)de los partidos
  2. Incluya cualquier espacio en blanco o no espacios ([\s\S]*)en blanco en las coincidencias
  3. Excluir etiqueta de cierre (?:<\/TAG>)de los partidos

3

¡Esta respuesta supone soporte para mirar alrededor! Esto me permitió identificar todo el texto entre pares de etiquetas de apertura y cierre. Ese es todo el texto entre el '>' y el '<'. Funciona porque mirar alrededor no consume los caracteres que coincide.

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

Lo probé en 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>

Es un juego de tres partes: la mirada hacia atrás, el contenido y la mirada hacia el 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 pantalla de regex101.com

Espero que sirva como un comienzo para 10. Suerte.


Gracias. No solo es una mejor respuesta, sino también un excelente enlace al sitio regex101. ¡Votado! 🙂
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 la respuesta aceptada es sin código javascript, entonces agregue eso:


1

preg_match_all(/<pre>([^>]*?)<\/pre>/,$content,$matches)esta expresión regular seleccionará todo entre etiquetas. no importa si está en una nueva línea (trabajar con multilínea.


1

En Python, establecer la DOTALLbandera capturará todo, incluidas las nuevas líneas.

Si se ha especificado el indicador DOTALL, esto coincide con cualquier carácter, incluida una nueva línea. 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!

Captura de texto entre todas las etiquetas de apertura y cierre en un documento

Para capturar texto entre todas las etiquetas de apertura y cierre en un documento, finditeres útil. En el siguiente ejemplo, tres <pre>etiquetas de apertura y cierre están presentes en la cadena.

#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 múltiples líneas:

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


0

Yo uso esta solución:

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

-1

En Javascript (entre otros), esto es simple. Cubre atributos y múltiples líneas:

/<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>

66
Presente / explique su respuesta usando palabras.
Andrew Regan
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.