Regex sélectionne tout le texte entre les balises

143

Quelle est la meilleure façon de sélectionner tout le texte entre 2 balises - ex: le texte entre toutes les balises «pré» de la page.

basheps
la source
2
Le meilleur moyen est d'utiliser un analyseur HTML comme "Beautiful Soup" si vous aimez le python ...
Fredrik Pihl
1
Le meilleur moyen est d'utiliser l'analyseur XML / HTML.
Daniel O'Hara
4
En général, utiliser des expressions régulières pour analyser le HTML n'est pas une bonne idée: stackoverflow.com/questions/1732348/…
murgatroid99
N'analysez pas le texte entre les balises avec regex car les balises imbriquées arbitrairement rendent le HTML non régulier. Les balises correspondantes semblent être acceptées. /<div>.*?<\/div>/.exec("<div><div></div></div>")
jdh8

Réponses:

157

Vous pouvez utiliser "<pre>(.*?)</pre>", (en remplaçant pre par le texte que vous voulez) et extraire le premier groupe (pour des instructions plus spécifiques, spécifiez une langue), mais cela suppose la notion simpliste que vous avez un HTML très simple et valide.

Comme d'autres commentateurs l'ont suggéré, si vous faites quelque chose de complexe, utilisez un analyseur HTML.

PyKing
la source
41
Cela ne sélectionne pas le texte entre les balises, cela inclut les balises.
capikaw
3
Vous devez saisir la sélection en utilisant ()
Sahu V Kumar
2
Pour les balises multilignes: <html_tag> (. +) ((\ S) + (. +)) + <\ / Html_tag>
Felipe Augusto
Cela a toujours de la visibilité, donc: si vous voyez toujours des <pre>balises après avoir essayé <pre>(.*?)<\/pre>, c'est parce que vous regardez ce qui est capturé par la correspondance complète au lieu du groupe de capture (. *?). Cela semble ringard mais je pense toujours "parenthèse = paire de voleurs" car à moins que le (soit suivi d'un ?comme dans (?:ou (?>, chaque match aura deux captures: 1 pour le match complet et 1 pour le groupe de capture. Chaque jeu supplémentaire de parenthèses ajoute une capture supplémentaire. Vous devez simplement savoir comment récupérer les deux captures dans la langue avec laquelle vous travaillez.
rbsdca
137

La balise peut être complétée sur une autre ligne. C'est pourquoi \ndoit être ajouté.

<PRE>(.|\n)*?<\/PRE>
zac
la source
5
Point important sur l'ajout (.|\n)*?lors du traitement des balises HTML sur plusieurs lignes. La réponse sélectionnée ne fonctionne que si les balises HTML sont sur la même ligne.
Caleuanhopkins
3
<PRE> (. | \ N | \ r \ n) *? <\ / PRE> pour les fins de ligne Windows
Marquer le
3
Ne jamais utiliser (.|\n)*?pour correspondre à un caractère. Utilisez toujours .avec le smodificateur (simple ligne). Ou une [\s\S]*?solution de contournement.
Wiktor Stribiżew
Je voulais sélectionner les commentaires de code dans notepad ++, donc en utilisant cette réponse, j'ai trouvé /\*(.|\n)*?\*/qui a fait le travail - merci
wkille le
réponse parfaite merci beaucoup
Omda
25

C'est ce que j'utiliserais.

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

Fondamentalement, ce qu'il fait est:

(?<=(<pre>))La sélection doit être précédée du <pre>tag

(\w|\d|\n|[().,\-:;@#$%^&*\[\]"'+–/\/®°⁰!?{}|~]| )Ceci est juste une expression régulière que je souhaite appliquer. Dans ce cas, il sélectionne une lettre ou un chiffre ou un caractère de nouvelle ligne ou certains caractères spéciaux répertoriés dans l'exemple entre crochets. Le caractère pipe |signifie simplement " OU ".

+?Le caractère Plus indique pour sélectionner un ou plusieurs des éléments ci-dessus - l'ordre n'a pas d'importance. Le point d'interrogation change le comportement par défaut de «gourmand» en «non gourmand».

(?=(</pre>))La sélection doit être ajoutée par la </pre>balise

entrez la description de l'image ici

En fonction de votre cas d'utilisation, vous devrez peut-être ajouter des modificateurs tels que ( i ou m )

  • i - insensible à la casse
  • m - recherche multiligne

Ici, j'ai effectué cette recherche dans Sublime Text afin de ne pas avoir à utiliser de modificateurs dans mon regex.

Javascript ne prend pas en charge lookbehind

L'exemple ci-dessus devrait fonctionner correctement avec des langages tels que PHP, Perl, Java ... Javascript, cependant, ne prend pas en charge lookbehind, nous devons donc oublier d'utiliser (?<=(<pre>))et chercher une sorte de solution de contournement. Peut-être simplement supprimer les quatre premiers caractères de notre résultat pour chaque sélection, comme ici Regex correspond au texte entre les balises

Regardez également la DOCUMENTATION JAVASCRIPT REGEX pour les parenthèses non capturantes

DevWL
la source
Notez que vous devez échapper les guillemets simples / doubles avec `pour mettre l'expression rationnelle dans une chaîne.
David Zwart le
18

utilisez le modèle ci-dessous pour obtenir du contenu entre les éléments. Remplacez [tag]par l'élément réel dont vous souhaitez extraire le contenu.

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

Parfois, les balises auront des attributs, comme les anchorbalises ayant href, puis utiliseront le modèle ci-dessous.

 <[tag][^>]*>(.+?)</[tag]>
Shravan Ramamurthy
la source
Essayez le premier exemple comme «<head> (. +?) </head>» et fonctionne comme prévu. Mais je n'ai aucun résultat avec le second.
Alex Byrth le
1
cela ne fonctionne pas. <[tag]>matchera <t>, <a>et<g>
Martin Schneider le
2
@ MA-Maddin - Je pense que vous avez manqué la Replace [tag] with the actual element you wish to extract the content frompartie.
LWC
2
Eh bien, oui. Celles-ci []auraient dû être complètement omises. Ce serait plus clair, en raison de leur signification dans RegEx et du fait que les gens scannent d'abord le code et lisent le texte après;)
Martin Schneider
15

Pour exclure les balises de délimitation:

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

(?<=<pre>) recherche du texte après <pre>

(?=</pre>) cherche du texte avant </pre>

Les résultats seront textuels à l'intérieur de la prebalise

Jean-Simon Collard
la source
Les personnes utilisant ce regard sur la réponse de @krishna thakor, qui peuvent également déterminer si le contenu a une nouvelle ligne entre les balises
KingKongCoder
Cela a aidé dans mon cas (pas besoin de considérer les nouvelles lignes). Merci.
Pking
6

Vous ne devriez pas essayer d'analyser le html avec des expressions régulières voir cette question et comment cela s'est avéré.

Dans les termes les plus simples, html n'est pas un langage régulier, vous ne pouvez donc pas analyser complètement avec des expressions régulières.

Cela dit, vous pouvez analyser des sous-ensembles de html lorsqu'il n'y a pas de balises similaires imbriquées. Donc, tant que quelque chose entre et n'est pas cette balise elle-même, cela fonctionnera:

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

Une meilleure idée est d'utiliser un analyseur, comme le DOMDocument natif, pour charger votre html, puis sélectionnez votre balise et obtenez le html interne qui pourrait ressembler à ceci:

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

Et comme il s'agit d'un analyseur approprié, il sera capable de gérer les balises d'imbrication, etc.

sg3s
la source
2
Je veux juste dire que je suis un peu dérangé par le fait que cela recueille toujours des votes négatifs alors que c'est la seule réponse qui fournit une solution appropriée à côté de l'expression régulière et j'ai également ajouté un avertissement suffisant que ce n'est probablement pas la bonne façon ... Au moins, commentez ce qui ne va pas dans ma réponse, s'il vous plaît.
sg3s
1
La question n'a pas été identifiée avec php. Je ne sais pas comment PHP est entré en scène ...
trincot
@trincot C'était il y a plus de 7 ans, donc je ne m'en souviens plus. Dans tous les cas, c'est un exemple de résolution du problème avec une regex et avec un analyseur. Le regex est bon et php est exactement ce que je connaissais bien à l'époque.
sg3s
Je comprends, j'ai vu votre premier commentaire et j'ai pensé que cela pourrait expliquer certains des votes négatifs.
trincot le
5

Essaye ça....

(?<=\<any_tag\>)(\s*.*\s*)(?=\<\/any_tag\>)
Heriberto Rivera
la source
3
Notez que regarder derrière n'est pas pris en charge dans JavaScript.
allicarn
Ooo bien sûr, mais cette regex est pour Java. merci pour votre note.
Heriberto Rivera
4

Cela semble être l'expression régulière la plus simple de tout ce que j'ai trouvé

(?:<TAG>)([\s\S]*)(?:<\/TAG>)
  1. Exclure la balise d'ouverture (?:<TAG>)des correspondances
  2. Incluez des espaces ou des caractères autres que des espaces ([\s\S]*)dans les correspondances
  3. Exclure la balise (?:<\/TAG>)de fermeture des correspondances
maqduni
la source
3

Cette réponse suppose un soutien pour regarder autour de vous! Cela m'a permis d'identifier tout le texte entre les paires de balises d'ouverture et de fermeture. C'est tout le texte entre le «>» et le «<». Cela fonctionne parce que regarder autour de vous ne consomme pas les caractères auxquels il correspond.

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

Je l'ai testé sur https://regex101.com/ en utilisant ce fragment 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>

C'est un jeu en trois parties: le regard derrière, le contenu et le regard vers l'avenir.

(?<=>)    # 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 '</'

capture d'écran de regex101.com

J'espère que cela sert de point de départ pour 10. Chance.

Clarius
la source
Je vous remercie. Non seulement c'est une meilleure réponse, mais aussi un excellent lien vers le site regex101. Vote positif! 🙂
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); });

Puisque la réponse acceptée est sans code javascript, donc en ajoutant que:

Shishir Arora
la source
1

preg_match_all(/<pre>([^>]*?)<\/pre>/,$content,$matches)cette expression régulière sélectionnera tout entre les balises. peu importe que ce soit dans la nouvelle ligne (travailler avec multiligne.

Krishna thakor
la source
1

En Python, la définition de l' DOTALLindicateur capturera tout, y compris les nouvelles lignes.

Si l'indicateur DOTALL a été spécifié, cela correspond à n'importe quel caractère, y compris une nouvelle ligne. 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!

Capture de texte entre toutes les balises d'ouverture et de fermeture d'un document

Pour capturer du texte entre toutes les balises d'ouverture et de fermeture dans un document, finditerest utile. Dans l'exemple ci-dessous, trois <pre>balises d' ouverture et de fermeture sont présentes dans la chaîne.

#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
John
la source
0

Pour plusieurs lignes:

<htmltag>(.+)((\s)+(.+))+</htmltag>
Dilip
la source
0

Vous pouvez utiliser Pattern pattern = Pattern.compile( "[^<'tagname'/>]" );

Ambrish Rajput
la source
0

J'utilise cette solution:

preg_match_all( '/<((?!<)(.|\n))*?\>/si',  $content, $new);
var_dump($new);
T.Todua
la source
-1

En Javascript (entre autres), c'est simple. Il couvre les attributs et plusieurs lignes:

/<pre[^>]*>([\s\S]*?)<\/pre>/
Jonathan
la source
-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>
user5988518
la source
6
Veuillez introduire / expliquer votre réponse en utilisant des mots.
Andrew Regan le