[regex] HTML strippen met uitzondering

Pagina: 1
Acties:

  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 06-10 13:51

pjvandesande

GC.Collect(head);

Topicstarter
Voor het strippen van tekst die vanuit Word of Excel word geplakt gebruik ik Regex. De expression die ik hiervoor gebruik bij een Replace ziet er als volgt uit:

code:
1
<span[^>]*>|</span>|<script[^>]*>|</script>|<%[^>]*%>|<asp:[^>]*>|<asp:[[[:alpha:]]+]*>|<embed[^>]*>|</embed>|<object[^>]*>|</object>|<applet[^>]*>|</applet>|<font[^>]*>|</font>|<div[^>]*>|</div>|<meta[^>]*>


Dit werkt allemaal prima, alle HTML word gestript. Nu is er alleen een nieuwe functionaliteit in het systeem gekomen waarbij de <font> tags niet gestript moeten worden als deze de class highlighted bevatten. Een voorbeeld om dit te verduidelijken:

String to strip
HTML:
1
Do <font class="highlighted">not</font> <font style="background-color:red;">move</font>!


Gewenste resultaat
HTML:
1
Do <font class="highlighted">not</font>move!


Ik heb nu al verschillende expressions geprobeert, bijvoorbeeld: <font[^highlighted]*>|</font>
Dit werkt prima, alleen de sluit tag (</font>) word wel verwijderd, terwijl dit niet gewenst is. Is er een manier om dit te voorkomen?

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 14:25

Janoz

Moderator Devschuur®

!litemod

Ik denk dat je zo langzamerhand uitkomt bij de limieten van reguliere expressies. Dit kun je waarschijnlijk beter oplossen met een stackbased parser.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
Zelfs als je die class="highlighted" zou weten te matchen (wat in theorie kan maar héél erg lelijk wordt), kun je niet op die manier een uitzondering maken omdat je dan nog geen idee hebt welke </font>-tag ermee correspondeert. Daarmee is dit probleem te vergelijken met het matchen van haakjes in een expressie (bv. zijn de haakjes in "(1 + 2)*(3/(4 + 5))" gebalanceerd?) en dat is fundamenteel onmogelijk met reguliere expressies.

Je zult dus op een andere manier moeten werken. Een simpele parse tree bouwen en dan de ongewenste tags eruit gooien (eventueel bij het reconstrueren) zoals Janoz suggeert is een goed idee.

  • EdwinG
  • Registratie: Oktober 2002
  • Laatst online: 30-11 19:23
Werkt:
code:
1
<font[^highlighted|>]*>[^</font>]*</font>

Misschien?
Je verwijderd op die manier per paar (dus open & sluittag tegelijk), en daarom zal de sluittag (volgens mij) ook niet verwijderd worden.

edit:
Je kunt hiermee nog wel tegen problemen lopen als je meerdere font-tags genest hebt.

[ Voor 19% gewijzigd door EdwinG op 14-11-2006 11:37 ]

Bezoek eens een willekeurige pagina


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
EdwinG schreef op dinsdag 14 november 2006 @ 11:36:
code:
1
<font[^highlighted|>]*>[^</font>]*</font>
Karakters tussen blokhaken specificeren een character class; je kunt op die manier geen hele strings 'niet' matchen.

  • EdwinG
  • Registratie: Oktober 2002
  • Laatst online: 30-11 19:23
Soultaker schreef op dinsdag 14 november 2006 @ 11:48:
Karakters tussen blokhaken specificeren een character class; je kunt op die manier geen hele strings 'niet' matchen.
Ah, op die manier.
Een string 'niet' matchen heb ik op die manier nog nooit geprobeerd.
Door de volgende regel uit de ts:
code:
1
<font[^highlighted]*>|</font>

Dacht ik dat dat wel mogelijk was.

Bezoek eens een willekeurige pagina


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 14:25

Janoz

Moderator Devschuur®

!litemod

Het grote probleem is dat een regex een patroon matched. Je kunt niet zeggen "deze string mag niet voorkomen". Je kunt wel een patroon opgeven die begint met '<font' en dan een stuk waarop "hightlight" niet te matchen is afgesloten door een '>'. Dit patroon is echter keurig toe te passen op <font class="hightlight">. Er is immers wel een manier om 'highlight' niet op 'class="highlight"' te laten passen. Leg de h maar eens samen met de c.

Daarnaast blijf je natuurlijk nog het probleem houden dat een regex geen enkele notie heeft van geneste structuren en daardoor niet kan zien welke open tag bij welke sluit tag hoort.

Misschien is het een idee om eens te kijken of je ook een dom parser kunt gebruiken. Je kunt dan heel simpel in de tree de nodes plat slaan met uitzodnering van de specifieke highlight nodes.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 14:58
@Janoz: het kan in theorie wel. Bijvoorbeeld een string waarin "abc" niet voorkomt kun je matchen met ^([^a]|a(?=$|[^ab]|b($|[^c])))+$. Zoals ik al zei: héél lelijk en ingewikkeld (en dit is nog een makkelijk voorbeeld omdat de letters niet meer dan eens voorkomen :X.

Reguliere expressies moeten geen doel op zich zijn; als ze zo ingewikkeld worden dat je ze nauwelijks meer kunt lezen en schrijven kun je beter op een andere methode overstappen.

edit:
Een Perl-style look-ahead toegevoegd... ik weet niet zo 1-2-3 of/hoe het zonder look-ahead kan...

[ Voor 35% gewijzigd door Soultaker op 14-11-2006 13:54 ]


  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 14:25

Janoz

Moderator Devschuur®

!litemod

Punt is dat het toch net iets anders gaat dan veel mensen verwachten. Je eigen regex voor een simpele abc laat dat wel zien. Je moet op zoek naar een patroon "Zorg dat elke 'a' waar een 'b' na komt nooit wordt gevolgd door een 'c'".

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


Verwijderd

Is het misschien een idee om de font tags er eerst uit te filteren met andere RegExp en de < > door bijv. een [ ] te vervangen, daarna je overige HTML eruit te filteren en dan weer RegExp die de [ & ] van de font tags vervangt naar < >

  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 06-10 13:51

pjvandesande

GC.Collect(head);

Topicstarter
Na jullie reacties heb ik besloten om maar zelf te parsen. Gelukkig zat ik al langer met deze vraag, ben vaker soortgelijke situaties tegengekomen en weet nu dat het in Regex niet makkelijk (lees onmogelijk is) dit te berijken.
Pagina: 1