Era un problema interessante (mi sono sempre piaciute le regexp), prima versione del pattern:
Fa uso di strumenti particolari: possessive quantifiers, negative lookahead e lazy quantifiers. Un buon sito di info e' www.regularexpressions.infocodice:#</?+(?!a|br).*?>#s
Spiegazione del pattern:
1. cerca un '<'
2. cerca un '/' opzionale (qui ho usato il possessive quantifier)
3. seguito da qualcosa che non e' 'a' o 'br'
4. cerca un carattere qualsiasi (con quantifier lazy)
5. cerca un '>'
Dettagli
2. il possessive quantifier qui e' necessario per evitare match indesiderati a causa del backtracking delle regexp, che di default fa di tutto pur di ottenere un match. Senza quel '+', il pattern avrebbe matchato anche </a> perche' lo slash sarebbe stato "acchiappato" dal punto che viene dopo. In questo modo gli si dice "cerca uno slash opzionale: se non c'e' ok, ma se c'e' e' mio e di nessun altro".
3. il negative lookahead in sostanza qui dice "dopo il '<' e lo slash opzionale non deve esserci a|br". Nota che lookahead e lookbehind sono "zero-width assertions" cioe' non contano come un carattere, sono solo un controllo; in altre parole non sono come una character class: puoi fare [a-z]+ ma non puoi fare (?!a|br)+
4. il lazy quantifier (i normali ripetitori seguiti dal '?') cambia il comportamento dell'engine, che di default e' "prendi piu' che puoi", in "prendi il meno che puoi". In pratica serve per fare cose come <.*?> invece di <[^>]+>
NOTA: il pattern e' migliorabile per quanto riguarda la parte "a|br", perche' scritto cosi' esclude solo i tag che INIZIANO per "a" o "br". Quindi un ipotetico tag <alfa> sarebbe escluso dall'eliminazione. Una versione migliorata:
che cerca tag che non abbiano "a" o "br" seguiti da blank space o '>' (il (?:..) e' solo la sintassi per raggruppare senza memorizzare il contenuto delle parentesi).codice:#</?+(?!(?:a|br)[\s>]).*?>#s
Spero sia abbastanza chiaro, senno' chiedi pure![]()