validator RegEx associa tag aperti ad eccezione dei tag autonomi XHTML




rex101 (24)

Se ti serve questo per PHP:

Le functionsDOM PHP non funzioneranno correttamente a meno che non sia formattato correttamente in XML. Non importa quanto sia migliore il loro uso per il resto dell'umanità.functions

simplehtmldom è buono, ma l'ho trovato un po 'buggy, ed è abbastanza pesante per la memoria [si bloccherà su pagine grandi.]

Non ho mai usato il QueryPath , quindi non posso commentare la sua utilità.

Un altro da provare è il mio DOMParser che è molto leggero sulle risorse e ho usato felicemente per un po '. Semplice da imparare e potente.

Per Python e Java sono stati pubblicati link simili.

Per i downvoters ho scritto solo la mia lezione quando i parser XML si sono dimostrati incapaci di resistere all'uso reale. Il downvoting religioso impedisce solo che vengano pubblicate risposte utili - mantieni le cose nella prospettiva della domanda, per favore.

Devo abbinare tutti questi tag di apertura:

<p>
<a href="foo">

Ma non questi:

<br />
<hr class="foo" />

Mi sono inventato questo e volevo assicurarmi di aver capito bene. Sto solo catturando l' az .

<([a-z]+) *[^/]*?>

Credo che dice:

  • Trova un meno di, quindi
  • Trova (e cattura) az una o più volte, quindi
  • Trova zero o più spazi, quindi
  • Trova qualsiasi carattere zero o più volte, avido, tranne / , quindi
  • Trova un più grande di

Ho ragione? E, cosa più importante, cosa ne pensi?


Sebbene le risposte che non puoi analizzare con espressioni regex siano corrette, non si applicano qui. L'OP vuole solo analizzare un tag HTML con espressioni regolari, e questo è qualcosa che può essere fatto con un'espressione regolare.

La regex suggerita è sbagliata, però:

<([a-z]+) *[^/]*?>

Se aggiungi qualcosa alla regex, tornando indietro può essere costretto ad abbinare cose stupide come <a >> , [^/] è troppo permissivo. Si noti inoltre che <space>*[^/]* è ridondante, poiché [^/]* può anche corrispondere agli spazi.

Il mio suggerimento sarebbe

<([a-z]+)[^>]*(?<!/)>

Dove (?<! ... ) è (in Perl regexes) l'aspetto negativo. Si legge "a <, quindi una parola, quindi tutto ciò che non è a>, l'ultimo dei quali potrebbe non essere un /, seguito da>".

Nota che questo consente cose come <a/ > (proprio come la regex originale), quindi se vuoi qualcosa di più restrittivo, devi costruire una <a/ > per abbinare coppie di attributi separate da spazi.


Ecco un parser basato su PHP che analizza l'HTML usando alcune regex non empiriche. Come autore di questo progetto, posso dirti che è possibile analizzare l'HTML con espressioni regolari, ma non efficiente. Se hai bisogno di una soluzione lato server (come ho fatto per il mio plug-in Wordpress wp-Typography ), funziona.


Disclaimer : usa un parser se hai l'opzione. Detto ciò...

Questa è la regex che uso (!) Per abbinare i tag HTML:

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>

Potrebbe non essere perfetto, ma ho eseguito questo codice attraverso un sacco di HTML. Nota che cattura anche cose strane come <a name="badgenerator""> , che <a name="badgenerator""> sul web.

Immagino che per far sì che non corrisponda ai tag autosufficienti, vorresti usare il look-behind negativo di Kobi :

<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+(?<!/\s*)>

o semplicemente combinare se e se non.

Per downvoters: questo è un codice funzionante da un prodotto reale. Dubito che chiunque legga questa pagina avrà l'impressione che sia socialmente accettabile usare espressioni regex su HTML.

Avvertenza : Devo notare che questa regex si rompe ancora in presenza di blocchi CDATA, commenti, elementi di script e di stile. La buona notizia è che puoi sbarazzarti di quelli che usano una regex ...


<\s*(\w+)[^/>]*>

Le parti hanno spiegato:

< : carattere iniziale

\s* : potrebbe avere spazi bianchi prima del nome del tag (brutto ma possibile).

(\w+): i tag possono contenere lettere e numeri (h1). Bene, \wcorrisponde anche a "_", ma non fa male, immagino. Se invece usi curioso ([a-zA-Z0-9] +).

[^/>]*: qualsiasi cosa tranne >e /fino alla chiusura>

> : chiusura >

estraneo

E ai borsisti che sottovalutano le espressioni regolari dicendo che sono potenti solo quanto le lingue regolari:

un n ba n ba n che non è regolare e nemmeno privo di contesto, può essere abbinato^(a+)b\1b\1$

Backreferencing FTW !


Mentre è vero che chiedere regex per analizzare HTML in modo arbitrario è come chiedere a un principiante di scrivere un sistema operativo, a volte è appropriato analizzare un set limitato e conosciuto di HTML.

Se si dispone di un piccolo set di pagine HTML da cui si desidera analizzare i dati e inserirli in un database, le regex potrebbero funzionare correttamente. Ad esempio, recentemente ho voluto ottenere i nomi, le parti e i distretti dei rappresentanti federali australiani, che ho ottenuto dal sito web del Parlamento. Questo era un lavoro limitato, una tantum.

Regexes ha funzionato bene per me ed è stato molto veloce da configurare.


Ci sono alcune espressioni regolari per sostituire HTML con BBCode here . Per tutti i nay-sayer, si noti che non sta tentando di analizzare completamente l'HTML, ma solo di disinfettarlo. Probabilmente si può permettere di uccidere tag che il suo semplice "parser" non riesce a capire.

Per esempio:

$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;

Ci sono persone che ti diranno che la Terra è rotonda (o forse che la Terra è uno sferoide oblato se vogliono usare strane parole). Stanno mentendo.

Ci sono persone che ti diranno che le espressioni regolari non dovrebbero essere ricorsive. Ti stanno limitando. Hanno bisogno di soggiogarti e lo fanno tenendoti nell'ignoranza.

Puoi vivere nella loro realtà o prendere la pillola rossa.

Come Lord Marshal (è un parente della classe Marshal .NET?), Ho visto l' Underverse Stack Based Regex-Verse e restituito con una conoscenza di poteri che non puoi immaginare. Sì, penso che ci fosse un vecchio o due che li proteggevano, ma stavano guardando il calcio in TV, quindi non è stato difficile.

Penso che il caso XML sia abbastanza semplice. Il RegEx (nella sintassi .NET), sgonfiato e codificato in base64 per renderlo più facile da comprendere dalla tua mente debole, dovrebbe essere qualcosa del genere:

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
+r/vD34mUADO1P4/AQAA//8=

Le opzioni da impostare sono RegexOptions.ExplicitCapture . Il gruppo di acquisizione che stai cercando è ELEMENTNAME . Se il gruppo di cattura ERROR non è vuoto, si è verificato un errore di analisi e il Regex si è interrotto.

Se hai problemi a riconvertirlo con una regex leggibile dall'uomo, questo dovrebbe aiutare:

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());
    }
}

Se non sei sicuro, no, NON sto scherzando (ma forse sto mentendo). Funzionerà. Ho provato un sacco di test unitari per testarlo, e ho persino usato (parte) i test di conformità . È un tokenizer, non un parser in piena regola, quindi dividerà l'XML solo nei suoi token componenti. Non analizzerà / integrerà DTD.

Oh ... se vuoi il codice sorgente della regex, con alcuni metodi ausiliari:

regex tokenken un xml o la regex full plain


Sebbene non sia adatto ed efficace usare espressioni regolari a tale scopo, a volte le espressioni regolari forniscono soluzioni rapide per problemi di corrispondenza semplici e, a mio modo di vedere, non è così orribile usare espressioni regolari per lavori banali.

C'è un post sul blog definitivo sulla corrispondenza degli elementi HTML più interni scritti da Steven Levithan.


Provare:

<([^\s]+)(\s[^>]*?)?(?<!/)>

È simile al tuo, ma l'ultimo >non deve essere dopo una barra, e accetta anche h1.


Non conosco il tuo esatto bisogno di questo, ma se stai usando anche .NET, non potresti usare Html Agility Pack ?

Estratto:

È una libreria di codice .NET che consente di analizzare file HTML "fuori dal web". Il parser è molto tollerante con l'HTML malformato del "mondo reale".


Vuoi il primo >non preceduto da a /. Guarda here per i dettagli su come farlo. Si riferisce a come lookbehind negativo.

Tuttavia, un'implementazione ingenua di questo finirà per corrispondere <bar/></foo>in questo documento di esempio

<foo><bar/></foo>

Puoi fornire qualche informazione in più sul problema che stai cercando di risolvere? Stai iterando programmando i tag?


Non è possibile analizzare [X] HTML con espressioni regolari. Perché HTML non può essere analizzato da regex. Regex non è uno strumento che può essere utilizzato per analizzare correttamente l'HTML. Come ho già risposto in domande HTML e regex qui tante volte in passato, l'uso della regex non ti permetterà di consumare HTML. Le espressioni regolari sono uno strumento non sufficientemente sofisticato per comprendere i costrutti utilizzati da HTML. HTML non è un linguaggio normale e quindi non può essere analizzato da espressioni regolari. Le query Regex non sono in grado di suddividere l'HTML nelle sue parti significative. tante volte ma non mi sta arrivando. Anche le espressioni regolari irregolari migliorate usate da Perl non sono all'altezza del compito di analizzare l'HTML. Non mi farai mai crackare. L'HTML è un linguaggio di complessità sufficiente che non può essere analizzato dalle espressioni regolari. Anche Jon Skeet non può analizzare l'HTML usando espressioni regolari. Ogni volta che provi ad analizzare l'HTML con espressioni regolari, l'empio bambino piange il sangue delle vergini e gli hacker russi bloccano la tua webapp. L'analisi di HTML con le espressioni regex ha contaminato le anime nel regno dei vivi. HTML e regex vanno insieme come l'amore, il matrimonio e l'infanticidio rituale. Il <center> non può trattenerlo è troppo tardi. La forza della regex e dell'HTML nello stesso spazio concettuale distruggerà la tua mente come un mastice così acquoso. Se analizzi l'HTML con espressioni regolari che stai cedendo a Loro e ai loro modi blasfemi che condannano tutti noi a un lavoro disumano per Colui il cui Nome non può essere espresso nel Piano Multilingue di base, viene. HTML-plus-regexp fluidificherà gli nerd del senziente mentre osservate, la vostra psiche appassisce nell'attacco dell'orrore. I parser HTML basati su Rege̿̔̉x sono il cancro che sta uccidendo è troppo tardi è troppo tardi non possiamo essere salvati la trangession di un chi͡ld assicura che regex consumerà tutto il tessuto vivente (tranne HTML che non può, come precedentemente profetizzato) caro signore aiutaci come può qualcuno sopravvivere a questo flagello usando regex per analizzare HTML ha condannato l'umanità a un'eternità di terribile tortura e buchi di sicurezza usando rege x come uno strumento per elaborare l'HTML stabilisce un brea ch tra questo mondo e il temuto regno di entità cocente (come Entità SGML, ma più corrotto) una semplice visione del mondo di ex parser di reg per HTML sarà in grado di trasportare la coscienza di un programmatore prima di un urlo incessante, arriva , la pestilenza di una regex-infezione wil l divorare il tuo HT ML parser, l'applicazione e l'esistenza di tutti i tempi come Visual Basic solo peggio arriva lui com es non combatteranno h e è, hi s Unholy Radiance de stro҉ying tutti ENLI ̈Ghtenment, i tag HTML che perde fr̶ǫm Yo ur occhi come liq uid p ain, il canto di regolare analisi exp re fissione si EXTI nguish le voci di Mor tal uomo da sp qui posso vedere che si può vederlo E 'bello il fatto che si inal snuf menzogne dell'Uomo TUTTO È LO SLATTO SULLA FACCIA che sta succedendo è lui che fa il suo io o è permeato al mio FAC E IL MIO FRONTE godh dio no NO NOOOO O ON Θ stop t un * ̶͑̾̾ ̅ͫ͏̙̤g͇̫͛͆̾ͫ̑͆l͖͉̗̩̳̟̍ͫͥͨ e̠̅s ͎a̧͈͖r̽̾̈́͒͑e n ot rè̑ͧ̌aͨl̘̝̙ͤ̾̆ ZA̡͊͠͝LGΌ ISͮ҉̯͈͕̹̘ T O͇̹̺Ɲ̴ȳ̳ TH̘ Ë͖̉ ͠P̯͍̭O̚ N̐Y̡ H̸̡̪̯ͨ͊̽̅̾Ȩ̬̩̾͛ͪ̈͘ ̶̧̨̹̭̯ͧ̾ͬC̷̙̝͖ͭ̏ͥͮ͟Oͮ͏̮̪̝͍M̖͊̒ͪͩͬ̚̚͜Ȇ̴̟̟͙̞ͩ͌͝ S̨̥̫͎̭ͯ̿̔

Hai provato a utilizzare un parser XML invece?

Nota del moderatore

Questo post è bloccato per impedire modifiche inappropriate al suo contenuto. Il post sembra esattamente come dovrebbe apparire - non ci sono problemi con il suo contenuto. Per favore non contrassegnarlo per la nostra attenzione.


Mi sembra che tu stia cercando di associare i tag senza "/" alla fine. Prova questo:

<([a-zA-Z][a-zA-Z0-9]*)[^>]*(?<!/)>

Recentemente ho scritto un disinfettante HTML in Java. Si basa su un approccio misto di espressioni regolari e codice Java. Personalmente odio le espressioni regolari e la sua follia (leggibilità, manutenibilità, ecc.), Ma se riduci la portata delle sue applicazioni potrebbe adattarsi alle tue esigenze. Ad ogni modo, il mio disinfettante usa una lista bianca per i tag HTML e una lista nera per alcuni attributi di stile.

Per tua comodità ho creato un parco giochi in modo da poter verificare se il codice corrisponde alle tue esigenze: parco giochi e codice Java . Il tuo feedback sarà apprezzato.

C'è un piccolo articolo che descrive questo lavoro sul mio blog: http://roberto.open-lab.com


Se stai semplicemente cercando di trovare quei tag (senza ambizioni di analisi) prova questa espressione regolare:

/<[^/]*?>/g

L'ho scritto in 30 secondi e testato qui: http://gskinner.com/RegExr/

Corrisponde ai tipi di tag che hai menzionato, ignorando i tipi che hai detto di voler ignorare.


Come molte persone hanno già sottolineato, l'HTML non è un linguaggio normale che può renderlo molto difficile da analizzare. La mia soluzione è di trasformarla in un normale linguaggio usando un programma ordinato e quindi di usare un parser XML per consumare i risultati. Ci sono molte buone opzioni per questo. Il mio programma è scritto usando Java con la libreria jtidy per trasformare l'HTML in XML e poi Jaxen in xpath nel risultato.


Non ascoltare questi ragazzi. Puoi totalmente analizzare le grammatiche context-free con regex se interrompi l'attività in parti più piccole. È possibile generare il modello corretto con uno script che fa ognuno di questi in ordine:

  1. Risolvi il problema dell'arresto.
  2. Piazza un cerchio.
  3. Elaborare il problema del venditore ambulante in O (log n) o meno. Se c'è qualcosa di più, si esaurirà la RAM e il motore si bloccherà.
  4. Il pattern sarà abbastanza grande, quindi assicurati di avere un algoritmo che comprime senza perdita di dati casuali.
  5. Quasi lì - basta dividere l'intera cosa per zero. Vai tranquillo.

Non ho ancora finito l'ultima parte, ma so che mi sto avvicinando. Continua a lanciare CthulhuRlyehWgahnaglFhtagnException s per qualche motivo, quindi ho intenzione di portarlo su VB 6 e utilizzare On Error Resume Next . Aggiornerò il codice una volta che indago su questa strana porta che si è appena aperta nel muro. Hmm.

PS Pierre de Fermat ha anche capito come farlo, ma il margine che stava scrivendo non era abbastanza grande per il codice.


Sono d'accordo che lo strumento giusto per analizzare XML e in particolare HTML è un parser e non un motore di espressioni regolari. Tuttavia, come altri hanno sottolineato, a volte l'uso di un'espressione regolare è più veloce, più facile e svolge il lavoro se si conosce il formato dei dati.

Microsoft ha in realtà una sezione di Best Practices for Regular Expressions in .NET Framework e parla specificamente di Consider [ing] l'origine di input .

Le espressioni regolari hanno dei limiti, ma hai considerato quanto segue?

Il framework .NET è unico quando si tratta di espressioni regolari in quanto supporta Balancing Group Definitions .

Per questo motivo, credo che tu possa analizzare XML usando espressioni regolari. Si noti, tuttavia, che deve essere XML valido (i browser sono molto tolleranti all'HTML e consentono una sintassi XML errata all'interno di HTML ). Ciò è possibile poiché "la definizione del gruppo di bilanciamento" consentirà al motore di espressioni regolari di agire come un PDA.

Citazione dall'articolo 1 citato sopra:

.NET Regular Expression Engine

Come descritto sopra, i costrutti correttamente bilanciati non possono essere descritti da un'espressione regolare. Tuttavia, il motore di espressioni regolari .NET fornisce alcuni costrutti che consentono di riconoscere i costrutti bilanciati.

  • (?<group>) : spinge il risultato catturato sullo stack di cattura con il gruppo di nomi.
  • (?<-group>) - apre la parte più alta catturata con il gruppo nome fuori dallo stack di cattura.
  • (?(group)yes|no) - corrisponde alla parte sì se esiste un gruppo con il gruppo nome altrimenti non corrisponde a nessuna parte.

Questi costrutti consentono un'espressione regolare .NET per emulare un PDA limitato, consentendo essenzialmente le versioni semplici delle operazioni stack: push, pop e empty. Le semplici operazioni equivalgono all'incremento, decremento e confronto rispettivamente a zero. Ciò consente al motore delle espressioni regolari .NET di riconoscere un sottoinsieme dei linguaggi context-free, in particolare quelli che richiedono solo un contatore semplice. Ciò a sua volta consente alle espressioni regolari .NET non tradizionali di riconoscere singoli costrutti correttamente bilanciati.

Considera la seguente espressione regolare:

(?=<ul\s+id="matchMe"\s+type="square"\s*>)
(?>
   <!-- .*? -->                  |
   <[^>]*/>                      |
   (?<opentag><(?!/)[^>]*[^/]>)  |
   (?<-opentag></[^>]*[^/]>)     |
   [^<>]*
)*
(?(opentag)(?!))

Usa le bandiere:

  • Linea singola
  • IgnorePatternWhitespace (non necessario se comprimi regex e rimuovi tutti gli spazi)
  • IgnoreCase (non necessario)

Espressione regolare spiegata (in linea)

(?=<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

Puoi provarlo su A Better .NET Regular Expression Tester .

Ho usato la fonte di esempio di:

<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 &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>
</div>
</body>
</html>

Questo ha trovato la corrispondenza:

   <ul id="matchMe" type="square">
      <li>stuff...</li>
      <li>more stuff</li>
      <li>
          <div>
               <span>still more</span>
               <ul>
                    <li>Another &gt;ul&lt;, oh my!</li>
                    <li>...</li>
               </ul>
          </div>
      </li>
   </ul>

anche se in realtà è venuto fuori in questo modo:

<ul id="matchMe" type="square">           <li>stuff...</li>           <li>more stuff</li>           <li>               <div>                    <span>still more</span>                    <ul>                         <li>Another &gt;ul&lt;, oh my!</li>                         <li>...</li>                    </ul>               </div>           </li>        </ul>

Infine, ho apprezzato molto l'articolo di Jeff Atwood: Parsing Html The Cthulhu Way . Abbastanza divertente, cita la risposta a questa domanda che attualmente ha più di 4k voti.


Sun Tzu, un antico stratega cinese, generale e filosofo, disse:

Si dice che se conosci i tuoi nemici e conosci te stesso, puoi vincere cento battaglie senza una perdita. Se conosci te stesso, ma non il tuo avversario, puoi vincere o perdere. Se non conosci né te stesso né il tuo nemico, rischierai sempre te stesso.

In questo caso il tuo nemico è HTML e tu sei o te stesso o regex. Potresti anche essere Perl con regex irregolare. Conosci l'HTML. Conosci te stesso.

Ho composto un haiku che descrive la natura dell'HTML.

HTML has
complexity exceeding
regular language.

Ho anche composto un haiku che descrive la natura della regex in Perl.

The regex you seek
is defined within the phrase
<([a-zA-Z]+)(?:[^>]*[^/]*)?>

Ecco la soluzione:

<?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]);
?>

Per testarlo in profondità, ho inserito i tag di chiusura automatica delle stringhe come:

  1. <hr />
  2. <br/>
  3. <br>

Ho anche inserito i tag con:

  1. un attributo
  2. più di un attributo
  3. attribuisce quale valore è associato tra virgolette singole o virgolette doppie
  4. attributi contenenti virgolette singole quando il delimitatore è una doppia virgola e viceversa
  5. attributi "unpretty" con uno spazio prima del simbolo "=", dopo di esso e sia prima che dopo di esso.

Se trovi qualcosa che non funziona nella dimostrazione del concetto di cui sopra, sono disponibile ad analizzare il codice per migliorare le mie capacità.

<EDIT> Ho dimenticato che la domanda da parte dell'utente era di evitare l'analisi dei tag a chiusura automatica. In questo caso il modello è più semplice, trasformandosi in questo:

$pattern = '/<(\w+)(\s+(\w+)\s*\=\s*(\'|")(.*?)\\4\s*)*\s*>/';

L'utente @ridgerunner ha notato che il pattern non consente attributi o attributi senza virgolette senza valore . In questo caso una regolazione fine ci porta il seguente schema:

$pattern = '/<(\w+)(\s+(\w+)(\s*\=\s*(\'|"|)(.*?)\\5\s*)?)*\s*>/';

</ EDIT>

Capire il modello

Se qualcuno è interessato a saperne di più sul modello, fornisco una linea:

  1. la prima sottoespressione (\ w +) corrisponde al nome del tag
  2. la seconda sottoespressione contiene il modello di un attributo. È composto da:
    1. uno o più spazi bianchi \ s +
    2. il nome dell'attributo (\ w +)
    3. zero o più spazi bianchi \ s * (è possibile o no, lasciando spazi vuoti qui)
    4. il simbolo "="
    5. di nuovo, zero o più spazi bianchi
    6. il delimitatore del valore dell'attributo, una virgoletta singola o doppia ('| "). Nel modello, la virgoletta singola viene sfuggita perché coincide con il delimitatore di stringa PHP. Questa sottoespressione viene catturata con le parentesi in modo che possa essere referenziata di nuovo per analizzare la chiusura dell'attributo, ecco perché è molto importante.
    7. il valore dell'attributo, corrispondente a quasi tutto: (. *?); in questa specifica sintassi, utilizzando la corrispondenza avida (il punto interrogativo dopo l'asterisco) il motore RegExp abilita un operatore "look-ahead", che corrisponde a qualsiasi cosa tranne ciò che segue questa sottoespressione
    8. ecco che arriva il divertimento: la parte \ 4 è un operatore backreference , che si riferisce ad una sotto-espressione definita prima nel pattern, in questo caso, mi riferisco alla quarta sotto-espressione, che è il primo delimitatore di attributo trovato
    9. zero o più spazi bianchi \ s *
    10. la sottoespressione dell'attributo termina qui, con la specifica di zero o più occorrenze possibili, data dall'asterisco.
  3. Quindi, poiché un tag può terminare con uno spazio bianco prima del simbolo ">", zero o più spazi bianchi sono abbinati al sottotest \ s *.
  4. Il tag da abbinare può terminare con un semplice simbolo ">", o una possibile chiusura XHTML, che fa uso della barra prima di essa: (/> |>). La barra, ovviamente, è sfuggita poiché coincide con il delimitatore dell'espressione regolare.

Piccolo suggerimento: per analizzare meglio questo codice è necessario guardare il codice sorgente generato poiché non ho fornito alcun carattere speciale di escape HTML.


Ho usato uno strumento open source chiamato HTMLParser prima. È progettato per analizzare l'HTML in vari modi e serve allo scopo abbastanza bene. Può analizzare HTML come treenode diverso e puoi facilmente utilizzare la sua API per ottenere attributi dal nodo. Guardalo e vedi se questo può aiutarti.


Ogni volta che ho bisogno di estrarre rapidamente qualcosa da un documento HTML, uso Tidy per convertirlo in XML e quindi utilizzare XPath o XSLT per ottenere ciò di cui ho bisogno. Nel tuo caso, qualcosa del genere:

//p/a[@href='foo']

Il W3C spiega l'analisi in forma pseudo regexp:
W3C Link

Segui i link per var QName, Se Attributeper avere un quadro più chiaro.
Sulla base di ciò è possibile creare una regexp piuttosto buona per gestire cose come i tag stripping.





xhtml