Toon posts:

[JS] RegExp - Match-probleem

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik heb dat ene boek over regexps besteld, dus tot die tijd toch nog wat regexp vragen op dit forum van mij. :)

Mijn probleem is dus het volgende: de regexp hieronder zou 'textfield' moeten teruggeven waneer er binnen vogelbekjes type="text" wordt aangetroffen. Echter, wanneer ik de regexp uitvoer matched hij steevast op 'textarea'. Hebben jullie enig idee wat ik fout doe?

JavaScript:
1
/<.+?type="text".+?name="(.+?)"(?=>|.+?>)|<.+?name="(.+?)".+?type="text"(?=>|.+?>)/.exec('<input name="textfield" type="text"><textarea name="textarea"></textarea>')

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Logisch, aangezien het eerste deel van je regexp (voor de OR) namelijk al matched, alleen niet op de plek die jij wilt ;)

Tags parsen is trouwens vrij tricky en zou ik zeker niet in 1 regexp willen oplossen. Hier is het gebruik van een functie als argument heel handig, zo kan je bijvoorbeeld eerst hele tags matchen, en die doorgeven aan een functie die vervolgens binnen die tag weer matched op attributen.

* crisp rommelt wat in de oude doos en vist er wat uit

Hier is een regexp die ik ooit heb gemaakt om tags (met eventuele sluittag) te selecteren:

JavaScript:
1
var regExpr = new RegExp('(<\/[^<>]+>|<[^<>]+\/>|<(link|meta)[^<>]+>|<[^<>]+>(<\/[^<>]+>)?|[^<]+)', 'gi');


en hier wat dingen om attributen te selecteren binnen een tag en er wat mee te doen:

JavaScript:
1
2
3
  tag = tag.replace(/(\w+)=([^> '"]*)(?= |>)/g, function($1,$2,$3) { return $2.toLowerCase()+'="'+$3+'"';; });
  tag = tag.replace(/(\w+)="([^"]*)"/g, function($1,$2,$3) { return property($2,$3); } );
  tag = tag.replace(/(\w+)='([^']*)'/g, function($1,$2,$3) { return property($2,$3); } );


dit is wat uit z'n verband gerukt natuurlijk, maar je ziet al waar de kneep 'm kan zitten bij het selecteren van attributen: ze kunnen tussen single quotes staan, tussen normale quotes, of zelfs helemaal niet tussen quotes; allemaal dingen om rekening mee te houden...

[ Voor 57% gewijzigd door crisp op 08-06-2004 22:16 ]

Intentionally left blank


Verwijderd

Topicstarter
Een functie als argument? Wat bedoel je daarmee? Kun je een voorbeeld geven?

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Verwijderd schreef op 08 juni 2004 @ 22:14:
Een functie als argument? Wat bedoel je daarmee? Kun je een voorbeeld geven?
zie boven ;)

maar goed, wat ik wou illustreren is dat als je echt een perfecte SGML-parser wil schrijven gebaseerd op enkel reguliere expressies je het bijna zeker nooit perfect zal krijgen.

Intentionally left blank


Verwijderd

Topicstarter
Aangezien de invoer alleen vanuit mijzelf wordt ingegeven, hoeft een dergelijke functie niet perfect te zijn gelukkig (aangezien ik nog veeeel meer te doen heb ;)).

Bedankt i.i.g. voor dat voorbeeld!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Verwijderd schreef op 08 juni 2004 @ 22:22:
Aangezien de invoer alleen vanuit mijzelf wordt ingegeven, hoeft een dergelijke functie niet perfect te zijn gelukkig (aangezien ik nog veeeel meer te doen heb ;).

Bedankt i.i.g. voor dat voorbeeld!
Dat scheelt en maakt het ook wat eenvoudiger :)

wat je dan kan doen is eerst matchen op iets als:

code:
1
/<\w+ .*?type="text".*?>/i


en de matches daaruit door zoiets halen:

code:
1
/ name="([\w-]+)"/i

Intentionally left blank


Verwijderd

Topicstarter
Ok. Bedankt!

Edit:

Maar waarom niet gewoon zo: /name="(.+?)"/i i.p.v. /name="([\w-]+)"/i?

[ Voor 81% gewijzigd door Verwijderd op 08-06-2004 22:47 ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Trouwens even een freubel die het wel in 1 keer zou moeten doen:

JavaScript:
1
var re = /<\w+ (name="([\w-]+)"|[^>])*?type="text"(name="([\w-]+)"|[^>])*?>/i


nadeel is natuurlijk dat de ene keer match[2] gevuld is en de andere keer match[4] al naar gelang de volgorde van de attributen.

Intentionally left blank


Verwijderd

Topicstarter
Ok. Ik ga even aan de slag. Bedankt voor de bloemen moeite.

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Verwijderd schreef op 08 juni 2004 @ 22:32:
Ok. Bedankt!

Edit:

Maar waarom niet gewoon zo: /name="(.+?)"/i i.p.v. /name="([\w-]+)"/i?
omdat een name attribuut sowieso alleen maar uit bepaalde tekens kan en mag bestaan (vooropgesteld dat het valide HTML is), dus waarom zou je dan op meer tekens matchen dan noodzakelijk is?

Intentionally left blank


Verwijderd

" mag sowieso niet in een attribuut staan dat ook dubbele quotes als 'delimiters' heeft.

Een attribuut waarde herken je het eenvoudigst als "[^"]*"|'[^']*'

[ Voor 19% gewijzigd door Verwijderd op 08-06-2004 23:02 . Reden: modifiers vergeten ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Wat Cheatah zegt is ook helemaal correct (in ieder geval voor name-attributen), vaak is een negated class ook te prefereren boven een dot-quantifier (al dan niet greedy).

Ik heb nog even wat interessant leesvoer opgezocht:

Mastering Regular Expressions - O'Reilly
Death to dot-star!

happy reading! :)

Ik zie nu trouwens dat ik in mijn voorbeelden boven in principe ook geen ungreedy modifier had hoeven gebruiken aangezien ik toch backtracking forceer; het kan echter wel uitmaken voor de snelheid.

[ Voor 30% gewijzigd door crisp op 09-06-2004 00:03 ]

Intentionally left blank


Verwijderd

Topicstarter
Ok. Ik maar eens even lezen dan. Mag je trouwens '[]' gebruiken in een name-attribuut volgens de regels voor valide html?

Verwijderd

Die RegEx parser loopt spaak als je > en < gaat gebruiken in attributen, zoals dat mogelijk is...(met een grote "meen ik")

code:
1
<b onclick="alert(4>5);">bar</b>

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Verwijderd schreef op 09 juni 2004 @ 17:30:
Die RegEx parser loopt spaak als je > en < gaat gebruiken in attributen, zoals dat mogelijk is...(met een grote "meen ik")

code:
1
<b onclick="alert(4>5);">bar</b>
binnen attributen dien je dat soort karakters dan ook te vervangen door enitities:

HTML:
1
<b onclick="alert(4>5);">bar</b>

Intentionally left blank


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 08:54

crisp

Devver

Pixelated

Verwijderd schreef op 09 juni 2004 @ 16:52:
Ok. Ik maar eens even lezen dan. Mag je trouwens '[]' gebruiken in een name-attribuut volgens de regels voor valide html?
nee, officieel niet. Een name attribuut mag letters, cijfers en het min-teken bevatten, en mag daarbij niet beginnen met een cijfer.

Intentionally left blank

Pagina: 1