Je dois faire correspondre toutes ces balises d'ouverture:
<p>
<a href="foo">
Mais pas ceux-ci:
<br />
<hr class="foo" />
Je suis venu avec cela et je voulais être sûr d'avoir bien compris. Je ne fais que capturer le a-z
.
<([a-z]+) *[^/]*?>
Je crois que cela dit:
/
, puisAi-je ce droit? Et plus important encore, qu'en pensez-vous?
Vous ne pouvez pas analyser [X] HTML avec regex. Parce que HTML ne peut pas être analysé par regex. Regex n'est pas un outil qui peut être utilisé pour analyser correctement le code HTML. Comme j'ai déjà répondu maintes fois aux questions HTML et regex, l'utilisation de regex ne vous permettra pas de consommer du HTML. Les expressions régulières sont un outil insuffisamment sophistiqué pour comprendre les concepts employés par HTML. HTML n'est pas un langage standard et ne peut donc pas être analysé par des expressions régulières. Les requêtes Regex ne sont pas équipées pour décomposer HTML en parties significatives. tant de fois mais ça ne me va pas. Même les expressions régulières irrégulières améliorées utilisées par Perl ne permettent pas d'analyser le code HTML. Tu ne me feras jamais craquer. HTML est un langage d'une complexité suffisante pour qu'il ne puisse pas être analysé par des expressions régulières. Même Jon Skeet ne peut pas analyser HTML à l'aide d'expressions régulières. Chaque fois que vous essayez d'analyser du HTML avec des expressions régulières, l'enfant impie pleure le sang des vierges et les pirates russes pwn votre webapp. Analyser HTML avec regex invoque des âmes contaminées dans le royaume des vivants. HTML et regex vont ensemble comme l'amour, le mariage et l'infanticide rituel. Le <centre> ne peut pas tenir, c'est trop tard. La force de l'expression rationnelle et du code HTML réunis dans le même espace conceptuel détruira votre esprit, à l'instar de beaucoup d'eau. Si vous analysez HTML avec regex, vous cédez à eux et à leurs manières blasphématoires qui nous condamnent tous à un travail inhumain pour celui dont le nom ne peut pas être exprimé dans le plan multilingue de base, il vient. HTML-plus-regexp va liquéfier les nerfs du sentient pendant que vous observez, votre psyché se fanant sous l’impact de l’horreur. Les analyseurs HTML basés sur Rege̿̔̉x sont le cancer qui tue StackOverflow il est trop tard il est trop tard nous ne pouvons pas être sauvés la trangession d'un chi ensuresld assure que la regex va consommer tous les tissus vivants (à l'exception du HTML qui ne peut pas, comme précédemment prophétisé) cher seigneur, aidez-nous, comment peut-on survivre à ce fléau? utiliser regex pour analyser HTML a condamné l'humanité à une éternité de torture et de brèches de sécurité en utilisant regex en tant qu'outil pour traiter HTML établit unech entre ce monde et le monde redouté des entités en panne (comme les entités SGML, mais plus corrompu) un simple coup d'œilse du monde de regex parseurs pour HTML insTant de transporter un pla conscience de rogrammer inà un world de crier sans cesse, il vient, le pestilent slsa regex-infection wilje dévore ton HTAnalyseur ML, application et existence de tous les temps comme Visual Basic, pire encore il vient il comes ne pas fiGht he com̡e̶s, h̵iS unhho͞ly radiańcé debalises HTML, balises HTML leaki̧n͘g fr̶ǫm ̡yo ͟ur eye͢s̸ ̛l̕ik͏e liqUid pain, la chanson de re̸gular exp reanalyse de ssion va extiNguish les voix de morhomme tal du spIci je peux le voir pouvez-vous voir ̲͚̖͔̙î̩́t̲͎̩̱͔́̋̀ il est beauil final snuf
fing ole mensonges of Man ALL IS LOŚ͖̩͇̗̪̏̈́T ALL I S LOST ee pon̷y il vients il vientes-il comois til ichou permeates all MON FACE MON FACE godh dieu no NO NOO̼O O NΘ arrêter til un * ̶͑̾̾ ̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨes ͎a̧͈͖r̽̾̈́͒͑e
n̑ͧ̌ rè̑ͧ̌aͨl̘̝̙̃ͤ͂̾̆ ZA̡͊͠͝LGΌ ISͮ̂҉̯͈͕̹̘̱ TO TH̘Ë͖́̉ ͠P̯͍̭O̚ N̐Y̡ H̸̡̪̯ͨ͊̽̅̾̎Ȩ̬̩̾͛ͪ̈́̀́͘ ̶̧̨̱̹̭̯ͧ̾ͬ C̷̙̲̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̲̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝S̨̥̫͎̭ͯ̿̔̀ͅ
Avez-vous essayé d'utiliser un analyseur XML à la place?
Note du modérateur
Cet article est verrouillé pour empêcher toute modification inappropriée de son contenu. Le message ressemble exactement à ce qu'il est censé être - il n’ya aucun problème avec son contenu. Veuillez ne pas le signaler à notre attention.
S'il est vrai que demander à l'expression rationnelle d'analyser arbitraire HTML revient à demander à un débutant d'écrire un système d'exploitation, il est parfois approprié d'analyser un ensemble limité, conn de HTML.
Si vous souhaitez regrouper un petit nombre de pages HTML, puis les insérer dans une base de données, les expressions rationnelles peuvent fonctionner correctement. Par exemple, j'ai récemment voulu obtenir les noms, les partis et les districts des représentants fédéraux australiens, que j'ai extraits du site Web du Parlement. C'était un travail limité et ponctuel.
Les regexes ont bien fonctionné pour moi et ont été très rapides à mettre en place.
Je pense que la faille ici est que HTML est un grammaire de Chomsky Type 2 (grammaire libre de contexte) et RegEx est un grammaire de Chomsky Type 3 (grammaire normale) . Etant donné qu'une grammaire de type 2 est fondamentalement plus complexe qu'une grammaire de type 3 (voir la hiérarchie de Chomsky ), elle est mathématiquement impossible analyser XML avec RegEx.
Mais beaucoup essaieront, certains diront même le succès - mais jusqu'à ce que d'autres trouvent la faute et vous fassent complètement perdre.
N'écoute pas ces gars. Vous pouvez totalement pouvez analyser des grammaires sans contexte avec regex si vous divisez la tâche en morceaux plus petits. Vous pouvez générer le modèle correct avec un script qui effectue chacune de ces tâches dans l’ordre:
Je n'ai pas tout à fait terminé la dernière partie moi-même, mais je sais que je me rapproche. Il continue à lancer CthulhuRlyehWgahnaglFhtagnException
s pour une raison quelconque, je vais donc le porter sur VB 6 et utiliser On Error Resume Next
. Je mettrai à jour le code une fois que j'aurai enquêté sur cette étrange porte qui vient de s'ouvrir dans le mur. Hmm.
P.S. Pierre de Fermat a également compris comment le faire, mais la marge dans laquelle il écrivait n'était pas assez grande pour le code.
Disclaimer : utilisez un analyseur si vous en avez la possibilité. Cela dit...
C'est la regex que j'utilise (!) Pour correspondre aux balises HTML:
<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>
Ce n'est peut-être pas parfait, mais j'ai exécuté ce code via un lot de HTML. Notez qu'il attrape même des choses étranges comme <a name="badgenerator"">
, qui apparaissent sur le Web.
Je suppose que pour que cela ne corresponde pas aux balises autonomes, vous pouvez aussi utiliser le look négatif de Kobi :
<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>
ou juste combiner si et si non.
Pour les utilisateurs bas: Ceci est un code fonctionnel issu d'un produit réel. Je doute que quiconque lisant cette page aura l’impression que l’utilisation de regexes en HTML est socialement acceptable.
Mise en garde : Je dois noter que cette expression rationnelle échoue toujours en présence de blocs CDATA, de commentaires et d'éléments de script et de style. La bonne nouvelle est que vous pouvez vous débarrasser de ceux qui utilisent une expression régulière ...
Certaines personnes vous diront que la Terre est ronde (ou peut-être que la Terre est un sphéroïde oblat si elles veulent utiliser des mots étranges). Ils mentent.
Certaines personnes vous diront que les expressions régulières ne doivent pas être récursives. Ils vous limitent. Ils ont besoin de vous subjuguer, et ils le font en vous gardant dans l'ignorance.
Vous pouvez vivre dans leur réalité ou prendre la pilule rouge.
Comme Lord Marshal (est-il un parent de la classe Marshal .NET?), J’ai vu le Underverse Verset basé sur la pile et renvoyé avec pouvoirs connaissances que vous ne pouvez pas imaginer. Oui, je pense qu’il y avait un ou deux vieux qui les protégeaient, mais ils regardaient le football à la télévision, alors ce n’était pas difficile.
Je pense que le cas XML est assez simple. Le RegEx (dans la syntaxe .NET), dégonflé et codé en base64 pour le rendre plus facile à comprendre par votre esprit faible, devrait ressembler à ceci:
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
+r/vD34mUADO1P4/AQAA//8=
Les options à définir sont RegexOptions.ExplicitCapture
. Le groupe de capture que vous recherchez est ELEMENTNAME
. Si le groupe de capture ERROR
n'est pas vide, une erreur d'analyse est survenue et la regex s'est arrêtée.
Si vous avez des problèmes pour le reconvertir en une expression rationnelle lisible par un humain, ceci devrait vous aider:
static string FromBase64(string str)
{
byte[] byteArray = Convert.FromBase64String(str);
using (var msIn = new MemoryStream(byteArray))
using (var msOut = new MemoryStream()) {
using (var ds = new DeflateStream(msIn, CompressionMode.Decompress)) {
ds.CopyTo(msOut);
}
return Encoding.UTF8.GetString(msOut.ToArray());
}
}
Si vous n'êtes pas sûr, non, je ne plaisante pas (mais peut-être que je mens). Ça va marcher. J'ai construit des tonnes de tests unitaires pour le tester, et j'ai même utilisé (une partie de) les tests de conformité . Il s'agit d'un tokenizer et non d'un analyseur complet. Il ne divisera donc que le XML en ses composants. Il ne va pas analyser/intégrer les DTD.
Oh ... si vous voulez le code source de la regex, avec quelques méthodes auxiliaires:
Dans Shell, vous pouvez analyser HTML en utilisant sed :
En relation (pourquoi vous ne devriez pas utiliser de correspondance d'expression régulière):
Je conviens que le bon outil pour analyser XML et , en particulier HTML , est un analyseur syntaxique et non un moteur d’expression régulière. Cependant, comme d'autres l'ont fait remarquer, l'utilisation d'une expression rationnelle est parfois plus rapide, plus simple et plus efficace si vous connaissez le format de données.
Microsoft a en fait une section de Meilleures pratiques pour les expressions régulières dans le .NET Framework et parle spécifiquement de Envisager la source d'entrée .
Les expressions régulières ont des limites, mais avez-vous pris en compte les éléments suivants?
Le framework .NET est unique en ce qui concerne les expressions régulières dans la mesure où il prend en charge définitions du groupe d'équilibrage .
Pour cette raison, je crois que vous POUVEZ analyser XML en utilisant des expressions régulières. Notez cependant qu'il doit être un code XML valide (). Les navigateurs sont très indulgents en HTML et autorisent une syntaxe XML incorrecte à l'intérieur de HTML ). Cela est possible car la "Définition du groupe d'équilibrage" permettra au moteur des expressions régulières d'agir en tant que PDA.
Citation de l'article 1 cité ci-dessus:
. Moteur d’expression régulière NET
Comme décrit ci-dessus, les constructions correctement équilibrées ne peuvent pas être décrites par une expression régulière. Cependant, le moteur des expressions régulières .NET fournit quelques constructions permettant de reconnaître les constructions équilibrées.
(?<group>)
- place le résultat capturé dans la pile de capture avec le groupe de noms.(?<-group>)
- affiche la capture la plus haute avec le groupe de noms de la pile de capture.(?(group)yes|no)
- correspond à la partie oui s'il existe un groupe portant le nom groupe sinon ne correspond à aucune partie.Ces constructions permettent à une expression régulière .NET d'émuler un PDA restreint en autorisant essentiellement des versions simples des opérations de pile: Push, pop et empty. Les opérations simples sont à peu près équivalentes à incrémenter, décrémenter et comparer à zéro respectivement. Cela permet au moteur des expressions régulières .NET de reconnaître un sous-ensemble des langages sans contexte, en particulier ceux qui ne nécessitent qu'un simple compteur. Cela permet aux expressions régulières .NET non traditionnelles de reconnaître des constructions individuelles correctement équilibrées.
Considérez l'expression régulière suivante:
(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
<!-- .*? --> |
<[^>]*/> |
(?<opentag><(?!/)[^>]*[^/]>) |
(?<-opentag></[^>]*[^/]>) |
[^<>]*
)*
(?(opentag)(?!))
Utilisez les drapeaux:
(?=<ul\s+id="matchMe"\s+type="square"\s*>) # match start with <ul id="matchMe"...
(?> # atomic group / don't backtrack (faster)
<!-- .*? --> | # match xml / html comment
<[^>]*/> | # self closing tag
(?<opentag><(?!/)[^>]*[^/]>) | # Push opening xml tag
(?<-opentag></[^>]*[^/]>) | # pop closing xml tag
[^<>]* # something between tags
)* # match as many xml tags as possible
(?(opentag)(?!)) # ensure no 'opentag' groups are on stack
Vous pouvez essayer ceci à n meilleur testeur d'expressions régulières .NET .
J'ai utilisé l'échantillon source de:
<html>
<body>
<div>
<br />
<ul id="matchMe" type="square">
<li>stuff...</li>
<li>more stuff</li>
<li>
<div>
<span>still more</span>
<ul>
<li>Another >ul<, oh my!</li>
<li>...</li>
</ul>
</div>
</li>
</ul>
</div>
</body>
</html>
Ceci a trouvé la correspondance:
<ul id="matchMe" type="square">
<li>stuff...</li>
<li>more stuff</li>
<li>
<div>
<span>still more</span>
<ul>
<li>Another >ul<, oh my!</li>
<li>...</li>
</ul>
</div>
</li>
</ul>
bien qu'il soit sorti comme ça:
<ul id="matchMe" type="square"> <li>stuff...</li> <li>more stuff</li> <li> <div> <span>still more</span> <ul> <li>Another >ul<, oh my!</li> <li>...</li> </ul> </div> </li> </ul>
Enfin, j'ai vraiment apprécié l'article de Jeff Atwood: Parsing Html The Cthulhu Way . Assez drôle, il cite la réponse à cette question qui compte actuellement plus de 4k voix.
Je suggère d'utiliser QueryPath pour analyser XML et HTML en PHP. C'est fondamentalement la même syntaxe que jQuery, sauf que c'est du côté serveur.
Bien que les réponses que vous ne pouvez pas analyser en HTML avec des expressions rationnelles soient correctes, elles ne s'appliquent pas ici. L'OP veut juste analyser une balise HTML avec des expressions rationnelles, ce qui peut être fait avec une expression régulière.
La regex suggérée est fausse, cependant:
<([a-z]+) *[^/]*?>
Si vous ajoutez quelque chose à la regex, en faisant un retour arrière, il peut être forcé de faire correspondre des choses stupides comme <a >>
, [^/]
est trop permissif. Notez également que <space>*[^/]*
est redondant, car le [^/]*
peut également correspondre à des espaces.
Ma suggestion serait
<([a-z]+)[^>]*(?<!/)>
Où (?<! ... )
est (dans les expressions rationnelles Perl) le négatif recherché. Il se lit "un <, puis un mot, puis tout ce qui n'est pas un>, dont le dernier ne peut pas être un/suivi de>".
Notez que cela permet des choses comme <a/ >
(tout comme la regex originale), donc si vous voulez quelque chose de plus restrictif, vous devez créer une regex pour faire correspondre les paires d'attributs séparées par des espaces.
Essayer:
<([^\s]+)(\s[^>]*?)?(?<!/)>
Il est similaire au vôtre, mais le dernier >
ne doit pas être après une barre oblique et accepte également h1
.
Sun Tzu, ancien stratège, général et philosophe chinois, a déclaré:
On dit que si vous connaissez vos ennemis et vous-même, vous pouvez gagner cent batailles sans une seule perte. Si vous ne connaissez que vous-même, mais pas votre adversaire, vous pouvez gagner ou perdre. Si vous ne connaissez ni vous ni votre ennemi, vous vous exposerez toujours à un danger.
Dans ce cas, votre ennemi est HTML et vous êtes soit vous-même, soit un regex. Vous pourriez même être Perl avec une regex irrégulière. Connaître le HTML. Se connaitre.
J'ai composé un haïku décrivant la nature du HTML.
HTML has
complexity exceeding
regular language.
J'ai également composé un haïku décrivant la nature de la regex en Perl.
The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>
<?php
$selfClosing = explode(',', 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed');
$html = '
<p><a href="#">foo</a></p>
<hr/>
<br/>
<div>name</div>';
$dom = new DOMDocument();
$dom->loadHTML($html);
$els = $dom->getElementsByTagName('*');
foreach ( $els as $el ) {
$nodeName = strtolower($el->nodeName);
if ( !in_array( $nodeName, $selfClosing ) ) {
var_dump( $nodeName );
}
}
Sortie:
string(4) "html"
string(4) "body"
string(1) "p"
string(1) "a"
string(3) "div"
Fondamentalement, définissez simplement les noms de nœuds d’éléments à fermeture automatique, chargez la chaîne HTML complète dans une bibliothèque DOM, récupérez tous les éléments, passez en boucle et filtrez ceux qui ne se ferment pas automatiquement et opérez-les.
Je suis sûr que vous savez déjà maintenant que vous ne devriez pas utiliser regex à cette fin.
Je ne connais pas votre besoin exact, mais si vous utilisez également .NET, ne pouvez-vous pas utiliser Html Agility Pack ?
Extrait:
Il s'agit d'une bibliothèque de code .NET qui vous permet d'analyser des fichiers HTML "hors du Web". L'analyseur est très tolérant avec le code HTML malformé du "monde réel".
Vous voulez que le premier >
ne soit pas précédé d'un /
. Regardez ici pour plus de détails sur la façon de le faire. C'est ce qu'on appelle un regard négatif.
Cependant, une implémentation naïve de cela finira par faire correspondre <bar/></foo>
dans cet exemple de document
<foo><bar/></foo>
Pouvez-vous fournir un peu plus d'informations sur le problème que vous essayez de résoudre? Est-ce que vous parcourez les balises par programmation?
Le W3C explique comment analyser une pseudo expression rationnelle:
Lien W3C
Suivez les liens var pour QName
, S
et Attribute
pour obtenir une image plus claire.
Sur cette base, vous pouvez créer une bonne expression rationnelle pour gérer des tâches telles que le retrait des balises.
Si vous en avez besoin pour PHP:
Le PHP DOMfonctions ne fonctionnera pas correctement s'il n'est pas correctement formaté en XML. Peu importe à quel point leur utilisation est meilleure pour le reste de l'humanité.
simplehtmldom c'est bien, mais je l'ai trouvé un peu bogué, et la mémoire est assez lourde [Va planter sur de grandes pages.]
Je n'ai jamais utilisé Querypath , donc je ne peux pas commenter sur son utilité.
Un autre à essayer est mon DOMParser , qui est très léger sur les ressources et que j'utilise avec bonheur depuis un certain temps. Simple à apprendre et puissant.
Pour Python et Java, des liens similaires ont été postés.
Pour les votants descendants - je n'ai écrit ma classe que lorsque les analyseurs syntaxiques XML se sont avérés incapables de résister à une utilisation réelle. Les votes religieux empêchent simplement l'affichage de réponses utiles - gardez les choses en perspective, s'il vous plaît.
Voici la solution:
<?php
// here's the pattern:
$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*(\/>|>)/';
// a string to parse:
$string = 'Hello, try clicking <a href="#paragraph">here</a>
<br/>and check out.<hr />
<h2>title</h2>
<a name ="paragraph" rel= "I\'m an anchor"></a>
Fine, <span title=\'highlight the "punch"\'>thanks<span>.
<div class = "clear"></div>
<br>';
// let's get the occurrences:
preg_match_all($pattern, $string, $matches, PREG_PATTERN_ORDER);
// print the result:
print_r($matches[0]);
?>
Pour le tester en profondeur, j'ai entré dans la chaîne des balises à fermeture automatique comme:
J'ai aussi entré des tags avec:
Si vous trouvez quelque chose qui ne fonctionne pas dans la preuve de concept ci-dessus, je suis disponible pour analyser le code afin d'améliorer mes compétences.
<EDIT> J'ai oublié que la question de l'utilisateur était d'éviter l'analyse des balises à fermeture automatique. Dans ce cas, le modèle est plus simple, se transformant en ceci:
$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*>/';
L'utilisateur @ridgerunner a remarqué que le modèle n'autorisait pas attributs non cités ou attributs sans valeur. Dans ce cas, un réglage précis nous apporte le modèle suivant:
$pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?)\\5\s*)?)*\s*>/';
</ EDIT>
Si quelqu'un est intéressé à en savoir plus sur le modèle, je fournis une ligne:
Petit conseil: pour mieux analyser ce code, il est nécessaire de consulter le code source généré car je n’ai fourni aucun caractère spécial HTML échappé.
Chaque fois que j'ai besoin d'extraire rapidement quelque chose d'un document HTML, j'utilise Tidy pour le convertir en XML, puis XPath ou XSLT pour obtenir ce dont j'ai besoin. Dans votre cas, quelque chose comme ça:
//p/a[@href='foo']
J'ai utilisé un outil open source appelé HTMLParser auparavant. Il est conçu pour analyser le HTML de différentes manières et répond parfaitement à cet objectif. Il peut analyser le code HTML en tant que code différent et vous pouvez facilement utiliser son API pour extraire des attributs du nœud. Vérifiez-le et voyez si cela peut vous aider.
J'aime analyser le HTML avec des expressions régulières. Je n'essaie pas d'analyser un HTML idiot délibérément brisé. Ce code est mon analyseur principal (édition Perl):
$_ = join "",<STDIN>; tr/\n\r \t/ /s; s/</\n</g; s/>/>\n/g; s/\n ?\n/\n/g;
s/^ ?\n//s; s/ $//s; print
Il s'appelle htmlsplit, divise le code HTML en lignes, avec une balise ou un bloc de texte sur chaque ligne. Les lignes peuvent ensuite être traitées avec d'autres outils de texte et scripts, tels que grep , sed , Perl, etc. Je ne plaisante même pas :) Profitez-en.
Il est assez simple de réaménager mon script Perl Slurp-everything-first en un streaming agréable, si vous souhaitez traiter d’énormes pages Web. Mais ce n'est pas vraiment nécessaire.
Je parie que je vais avoir un vote négatif pour cela.
Contre mon attente, cela a eu quelques votes positifs, je vais donc suggérer quelques expressions plus précises:
/(<.*?>|[^<]+)\s*/g # get tags and text
/(\w+)="(.*?)"/g # get attibutes
Ils sont bons pour XML/XHTML.
Avec des variations mineures, il peut faire face au HTML désordonné ... ou convertir le HTML -> XHTML en premier.
Le meilleur moyen d'écrire des expressions régulières est d'utiliser le style Lex / Yacc , et non comme un trait opaque ou des monstruosités multilignes commentées. Je ne l'ai pas encore fait ici. ceux-là en ont à peine besoin.
Voici un analyseur basé sur PHP qui analyse HTML en utilisant des expressions rationnelles impies. En tant qu'auteur de ce projet, je peux vous dire qu'il est possible d'analyser le code HTML avec regex, mais sans efficacité. Si vous avez besoin d’une solution côté serveur (comme je l’ai fait pour mon plugin wp-Typography WordPress =) ), cela fonctionne.
Il existe quelques regex de Nice pour remplacer HTML par BBCode ici . Notez bien qu'il n'essaie pas d'analyser complètement le code HTML, mais simplement de le désinfecter. Il peut probablement se permettre de supprimer des tags que son simple "analyseur" ne peut pas comprendre.
Par exemple:
$store =~ s/http:/http:\/\//gi;
$store =~ s/https:/https:\/\//gi;
$baseurl = $store;
if (!$query->param("ascii")) {
$html =~ s/\s\s+/\n/gi;
$html =~ s/<pre(.*?)>(.*?)<\/pre>/\[code]$2\[\/code]/sgmi;
}
$html =~ s/\n//gi;
$html =~ s/\r\r//gi;
$html =~ s/$baseurl//gi;
$html =~ s/<h[1-7](.*?)>(.*?)<\/h[1-7]>/\n\[b]$2\[\/b]\n/sgmi;
$html =~ s/<p>/\n\n/gi;
$html =~ s/<br(.*?)>/\n/gi;
$html =~ s/<textarea(.*?)>(.*?)<\/textarea>/\[code]$2\[\/code]/sgmi;
$html =~ s/<b>(.*?)<\/b>/\[b]$1\[\/b]/gi;
$html =~ s/<i>(.*?)<\/i>/\[i]$1\[\/i]/gi;
$html =~ s/<u>(.*?)<\/u>/\[u]$1\[\/u]/gi;
$html =~ s/<em>(.*?)<\/em>/\[i]$1\[\/i]/gi;
$html =~ s/<strong>(.*?)<\/strong>/\[b]$1\[\/b]/gi;
$html =~ s/<cite>(.*?)<\/cite>/\[i]$1\[\/i]/gi;
$html =~ s/<font color="(.*?)">(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<font color=(.*?)>(.*?)<\/font>/\[color=$1]$2\[\/color]/sgmi;
$html =~ s/<link(.*?)>//gi;
$html =~ s/<li(.*?)>(.*?)<\/li>/\[\*]$2/gi;
$html =~ s/<ul(.*?)>/\[list]/gi;
$html =~ s/<\/ul>/\[\/list]/gi;
$html =~ s/<div>/\n/gi;
$html =~ s/<\/div>/\n/gi;
$html =~ s/<td(.*?)>/ /gi;
$html =~ s/<tr(.*?)>/\n/gi;
$html =~ s/<img(.*?)src="(.*?)"(.*?)>/\[img]$baseurl\/$2\[\/img]/gi;
$html =~ s/<a(.*?)href="(.*?)"(.*?)>(.*?)<\/a>/\[url=$baseurl\/$2]$4\[\/url]/gi;
$html =~ s/\[url=$baseurl\/http:\/\/(.*?)](.*?)\[\/url]/\[url=http:\/\/$1]$2\[\/url]/gi;
$html =~ s/\[img]$baseurl\/http:\/\/(.*?)\[\/img]/\[img]http:\/\/$1\[\/img]/gi;
$html =~ s/<head>(.*?)<\/head>//sgmi;
$html =~ s/<object>(.*?)<\/object>//sgmi;
$html =~ s/<script(.*?)>(.*?)<\/script>//sgmi;
$html =~ s/<style(.*?)>(.*?)<\/style>//sgmi;
$html =~ s/<title>(.*?)<\/title>//sgmi;
$html =~ s/<!--(.*?)-->/\n/sgmi;
$html =~ s/\/\//\//gi;
$html =~ s/http:\//http:\/\//gi;
$html =~ s/https:\//https:\/\//gi;
$html =~ s/<(?:[^>'"]*|(['"]).*?\1)*>//gsi;
$html =~ s/\r\r//gi;
$html =~ s/\[img]\//\[img]/gi;
$html =~ s/\[url=\//\[url=/gi;
Sur la question des méthodes RegExp pour analyser (x) HTML, la réponse à tous ceux qui ont parlé de certaines limites est la suivante: vous n’avez pas été suffisamment entraîné pour contrôler la force de cette arme puissante, depuis PERSONNE a parlé ici de récursivité .
Un collègue indépendant de RegExp m'a informé de cette discussion, qui n'est certainement pas la première du web sur ce sujet ancien et d'actualité.
Après avoir lu quelques articles, la première chose que j'ai faite a été de rechercher la chaîne "? R" dans ce fil. La seconde était de chercher "récursivité".
Non, vache sacrée, aucune correspondance n'a été trouvée.
Comme personne n’a mentionné le mécanisme principal sur lequel est construit un analyseur, j’ai vite compris que personne n’avait compris.
Si un analyseur (x) HTML a besoin de récursivité, un analyseur RegExp sans récursion ne suffit pas. C'est une construction simple.
Il est difficile de maîtriser l'art noir de RegExp . Il existe donc peut-être d'autres possibilités que nous avons laissées de côté lorsque nous essayons de tester notre solution personnelle pour capturer tout le Web. une main ... eh bien, j'en suis sûr :)
Voici le modèle magique:
$pattern = "/<([\w]+)([^>]*?)(([\s]*\/>)|(>((([^<]*?|<\!\-\-.*?\-\->)|(?R))*)<\/\\1[\s]*>))/s";
Juste l'essayer.
Il est écrit sous la forme d'une chaîne PHP. Le modificateur "s" permet donc aux classes d'inclure des nouvelles lignes.
Voici un exemple de note sur le manuel PHP que j'ai écrit en janvier: Référence
(Attention, dans cette note, j’ai utilisé à tort le modificateur "m"; il devrait être effacé, même s’il est ignoré par le moteur RegExp, car aucun ^ ou $ anchorage n’a été utilisé).
Nous pouvons maintenant parler des limites de cette méthode d’un point de vue plus éclairé:
Quoi qu'il en soit, il ne s'agit que d'un modèle RegExp, mais il révèle la possibilité de développer de nombreuses implémentations puissantes.
J'ai écrit ce modèle pour alimenter le analyseur de descente récursif d'un moteur de gabarit que j'ai construit dans mon framework, et les performances sont vraiment excellentes, que ce soit en temps d'exécution ou en mémoire. utilisation (rien à voir avec les autres moteurs de template qui utilisent la même syntaxe).
Comme de nombreuses personnes l’ont déjà souligné, le langage HTML n’est pas un langage courant, ce qui peut rendre l’analyse très difficile. Ma solution consiste à le transformer en un langage standard à l'aide d'un programme ordonné, puis à utiliser un analyseur XML pour utiliser les résultats. Il y a beaucoup de bonnes options pour cela. Mon programme est écrit en utilisant Java avec la bibliothèque jtidy pour convertir le code HTML en XML, puis Jaxen pour xpath dans le résultat.
<\s*(\w+)[^/>]*>
Les parties expliquées:
<
: caractère de départ
\s*
: il peut y avoir des espaces avant le nom de la balise (moche mais possible).
(\w+)
: les étiquettes peuvent contenir des lettres et des chiffres (h1). Eh bien, \w
correspond également à '_', mais cela ne fait pas de mal, je suppose. Si vous êtes curieux, utilisez plutôt ([a-zA-Z0-9] +).
[^/>]*
: tout sauf >
et /
jusqu'à la fermeture de >
>
: fermer >
Et aux gens qui sous-estiment les expressions régulières en disant qu’elles n’ont que le pouvoir des langages ordinaires:
unenbanban qui n'est pas régulier ni même dépourvu de contexte, peut être associé à ^(a+)b\1b\1$
Références arrière FTW !
Si vous essayez simplement de trouver ces balises (sans ambitions d'analyse), essayez cette expression régulière:
/<[^/]*?>/g
Je l'ai écrit en 30 secondes et testé ici: http://gskinner.com/RegExr/
Il correspond aux types de balises que vous avez mentionnés, tout en ignorant les types que vous avez dit vouloir ignorer.
Il me semble que vous essayez de faire correspondre les balises sans "/" à la fin. Essaye ça:
<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>
Il est vrai que lors de la programmation, il est généralement préférable d'utiliser des analyseurs syntaxiques et des API dédiés plutôt que des expressions régulières lors de l'utilisation de HTML, en particulier si la précision est primordiale (par exemple, si votre traitement peut avoir des implications en termes de sécurité). Cependant, je ne pense pas à une vue dogmatique que le balisage de style XML ne devrait jamais être traité avec des expressions régulières. Il existe des cas où les expressions régulières constituent un excellent outil pour le travail, par exemple lors de modifications ponctuelles dans un éditeur de texte, de la réparation de fichiers XML cassés ou de la gestion de formats de fichiers qui ressemblent mais ne sont pas tout à fait au format XML. Il y a certains problèmes à connaître, mais ils ne sont ni insurmontables ni même nécessairement pertinents.
Une expression rationnelle simple telle que <([^>"']|"[^"]*"|'[^']*')*>
est généralement suffisante, dans des cas tels que ceux que je viens de mentionner. C'est une solution naïve, tout bien considéré, mais elle autorise correctement les symboles >
non codés dans les valeurs d'attribut. Si vous recherchez, par exemple, une balise table
, vous pouvez l’adapter en tant que </?table\b([^>"']|"[^"]*"|'[^']*')*>
.
Juste pour donner une idée de ce à quoi ressemblerait une regex HTML plus "avancée", voici un travail assez respectable consistant à émuler le comportement de navigateur dans le monde réel et l'algorithme d'analyse HTML5:
</?([A-Za-z][^\s>/]*)(?:=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)|[^>])*(?:>|$)
Les éléments suivants correspondent à une définition assez stricte des balises XML (bien qu'elle ne tienne pas compte de l'ensemble des caractères Unicode autorisés dans les noms XML):
<(?:([_:A-Z][-.:\w]*)(?:\s+[_:A-Z][-.:\w]*\s*=\s*(?:"[^"]*"|'[^']*'))*\s*/?|/([_:A-Z][-.:\w]*)\s*)>
Certes, ils ne tiennent pas compte du contexte et de quelques cas Edge, mais même de tels problèmes pourraient être traités si vous le souhaitiez vraiment (par exemple, en effectuant une recherche entre les correspondances d'une autre expression rationnelle).
À la fin de la journée, utilisez l'outil le plus approprié pour le travail, même dans les cas où cet outil se trouve être une regex.
Bien qu’il ne soit ni approprié ni efficace d’utiliser des expressions régulières à cette fin, celles-ci apportent parfois des solutions rapides aux problèmes de correspondance simples et, à mon avis, il n’est pas si horrible d’utiliser des expressions régulières pour des travaux triviaux.
Il y a un billet de blog définitif à propos de la correspondance des éléments HTML les plus internes écrits par Steven Levithan.
Si vous ne voulez que les noms de balises, il devrait être possible de le faire par regex.
<([a-zA-Z]+)(?:[^>]*[^/] *)?>
devrait faire ce dont vous avez besoin. Mais je pense que la solution de "moritz" est déjà bien. Je ne l'ai pas vu au début.
Pour tous les votants: Dans certains cas, il est logique d'utiliser regex, car il peut s'agir de la solution la plus simple et la plus rapide. Je conviens qu'en général, vous ne devriez pas analyser HTML avec regex. Mais regex peut être un outil très puissant lorsque vous avez un sous-ensemble de HTML où vous connaissez le format et souhaitez extraire certaines valeurs. Je l'ai fait des centaines de fois et presque toujours obtenu ce que je voulais.
Le PO ne semble pas dire ce qu'il doit faire avec les balises. Par exemple, doit-il extraire du texte interne ou simplement examiner les balises?
Je suis fermement dans le camp qui dit que RegEx n'est pas le meilleur analyseur de texte. J'ai écrit une grande quantité de code d'analyse de texte comprenant ce code pour analyser les balises HTML .
Bien qu'il soit vrai que je ne suis pas génial avec RegEx, je considère les expressions rationnelles comme trop rigides et difficiles à conserver pour ce type d'analyse.
Cela peut faire:
<.*?[^/]>
Ou sans les balises de fin:
<[^/].*?[^/]>
Qu'en est-il des guerres de flammes sur les analyseurs HTML? Les analyseurs HTML doivent analyser (et reconstruire!) L'intégralité du document avant qu'il ne puisse classer votre recherche. Les expressions régulières peuvent être plus rapides/élégantes dans certaines circonstances. Mes 2 centimes ...
Je pense que cela pourrait fonctionner
<[a-z][^<>]*(?:(?:[^/]\s*)|(?:\s*[^/]))>
Et cela pourrait être testé ici .
Les éléments XML doivent suivre ces règles de nommage:
Et le modèle que j'ai utilisé va respecter ces règles.