[PHP] Hulp gevraagd bij opbouwen expressie

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Joen
  • Registratie: Juli 2003
  • Laatst online: 09-08 18:34
Ik ben bezig een soort van webmail-systeem te bouwen, maar zit een probleempje.
Ik heb vrijwel geen kennis van expressies, maar wil wel graag het volgende:

De input die ik krijg voor een afzender is:
code:
1
"Jantje" <jantje@beton.nl>
en soms:
code:
1
Jantje <jantje@beton.nl>
zonder de quotes dus.
Wat ik graag als output voor dit voorbeeld zou zien:
code:
1
<a href="mailto.php?toname=Jantje&toemail=jantje@beton.nl">Jantje</a>

Als het nodig is kan ik de invoer ook non-HTML maken, dus dat ", < en > gewoon normaal zijn als dit makkelijk is voor het maken van de expressie.

Dus: zou iemand mij kunne helpen aan de juiste expressie (voor bijvoorbeeld in preg_replace of zo)?

Acties:
  • 0 Henk 'm!

  • Joen
  • Registratie: Juli 2003
  • Laatst online: 09-08 18:34
Verrek.. die's zo duidelijk dat t me dit (door ook een beetje aanpassen van een andere preg_replace) in 1 keer lukt. :*)
PHP:
1
2
3
4
5
<?php
$string="\"Jeroen\" <jeroen@NOSPAMjoenlog.tk>";
$string = preg_replace("/\"?(.*?)\"? <(.*?)>/s","1 = \\1 | 2 = \\2",$string);
echo $string;
?>
Geeft als output:
code:
1
1 = Jeroen | 2 = jeroen@NOSPAMjoenlog.tk
En dat is exact wat ik ndig had. :)

[ Voor 14% gewijzigd door Joen op 02-02-2004 21:00 ]


Acties:
  • 0 Henk 'm!

  • vinnux
  • Registratie: Maart 2001
  • Niet online
JeroenM_tbs schreef op 02 februari 2004 @ 20:59:
Verrek.. die's zo duidelijk dat t me dit (door ook een beetje aanpassen van een andere preg_replace) in 1 keer lukt. :*)
Maar begrijp je ook wat ie precies doet?
Iets kopieren en ligt aanpassen wil nog niet zeggen dat je het begrijpt.
Begrip is belangrijker denk ik ;)

[ Voor 32% gewijzigd door vinnux op 02-02-2004 21:06 ]


Acties:
  • 0 Henk 'm!

  • Joen
  • Registratie: Juli 2003
  • Laatst online: 09-08 18:34
vgouw schreef op 02 februari 2004 @ 21:05:
[...]

Maar begrijp je ook wat ie precies doet?
Iets kopieren en ligt aanpassen wil nog niet zeggen dat je het begrijpt.
Begrip is belangrijker denk ik ;)
Erg goed van je dat je die vraag stelt ;) :P
Voorkomt allicht nieuwe topics er over :P

Ik moest er een link van maken naar een andere pagina dus is de expressie zo geworden:
PHP:
1
2
3
<?php
$fromnew = preg_replace("/\"?(.*?)\"? <(.*?)>/s","<a href=\"mail.php?toname=\\1&toaddress=\\2\">\\1</a>",$from);
?>

$fromnew bevat de input:
code:
1
"Jeroen" <jeroen@NOSPAMjoenlog.tk>
en $from (aan het einde in de preg_replace) geeft de output:
code:
1
<a href="mail.php?toname=Jeroen&toaddress=jeroen@NOSPAMjoenlog.tk">Jeroen</a>

Dan binnen de preg_replace:
- de eerste / geeft het begin aan
- \" geeft aan dat er quote in kan voorkomen
- de ? er direct achter geeft aan dat het voorgaande teken (de quote dus) niet per se hoeft voor te komen
- () geeft een bereik aan die je wilt opvangen en .*? geeft aan dat de waarde 0 of meer tekens mag bevatten
- \"? geeft weer aan dat het een quote MAG bevatten
- [spatie]< is gewone tekst die in de string MOET voorkomen
- (.*?) vangt weer een bereik op van 0 of meer karakters
- > is gewone tekst en MOET voorkomen
De /s switch weet ik zo niet meer.

Klopt mn beredenering zo?

Ik heb me wel eens een klein beetje verdiept in expressies met behulp van deze uitleg:
http://regexpstudio.com/TRegExpr/Help/RegExp_Syntax.html
Maar vind bovenstaande nederlandse uitleg toch wel een goede aanvulling en plezieriger leesbaar :)
Vooral de vraagteken om aan te geven dat het voorafgaande karakter optioneel is had ik nog nooit zo geweten en was ene belangrijke die ik zocht. :)

Hardstikke bedankt voor t linkje iig. ;)

[ Voor 21% gewijzigd door Joen op 02-02-2004 21:16 ]


Acties:
  • 0 Henk 'm!

  • vinnux
  • Registratie: Maart 2001
  • Niet online
Uitslover :P
Maar zo hebben beginnende mensen er ook zeker iets aan :D

[ Voor 72% gewijzigd door vinnux op 02-02-2004 21:42 ]


Acties:
  • 0 Henk 'm!

  • Joen
  • Registratie: Juli 2003
  • Laatst online: 09-08 18:34
vgouw schreef op 02 februari 2004 @ 21:41:
Uitslover :P
Maar zo hebben beginnende mensen er ook zeker iets aan :D
offtopic:
Uistlover? :?
Je vroeg er zelf min of meer om :P
Maar goed, ik heb het zo uitgebreid mogelijk uitgelegd zoals ik er zelf van begrijp en een ander heeft er idd zo ook iets aan dan. ;)
Maar nu weet ik nog niet of mn verhaaltje ook klopt... :P

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

je verhaal klopt inderdaad, wel 2 aanvullingen:

(.*?) - captured een match; de ? na de quantifier geeft aan dat er ungreedy gematched moet worden
/s - (s-modifier) betekent linespanning, of eigenlijk PCRE-DOTALL wat wil zeggen dat de . ook newlines matched

De PHP manual is ook heel duidelijk naar mijn mening:
http://nl3.php.net/manual/en/pcre.pattern.modifiers.php
http://nl3.php.net/manual/en/pcre.pattern.syntax.php

:)

edit: nog wat dingetjes :)

De / / om de regexp heen heten delimiters en kunnen in PHP ook andere karakters zijn, echter wordt de forward slash in talen als Perl en JS tevens gebruikt als constructor voor reguliere expressies, dus die zijn wel zo'n beetje standaard.

Er zijn verschillende quantifiers:

{x} matched precies x-maal het voorgaande karakter of sequence (omgeven door () )
{x,y} matched x tot y maal het voorgaande karakter of sequence
* matched 0 of meer keer een karakter of sequence (equivalent aan {0,} )
+ matched 1 of meer keer een karakter of sequence (equivalent aan {1,} )
? matched 0 of 1 keer een karakter of sequence (equivalent aan {0,1} )

Een quantifier gevolgt door een ? is dus een ungreedy match; je kan ook de hele regexp ungreedy maken met de U-modifier. Default is een match dus greedy wat wil zeggen dat er zoveel mogelijk gematched wordt zonder rekening te houden met wat de regulier expressie daarna vermeld. Bij een ungreedy match wordt daar wel rekening mee gehouden. Voorbeeld:

code:
1
2
3
string = 'abcdefg';
regexp = '/abc(.*)efg/'; // (.*) matched hier 'defg' in de string (zoveel mogelijk)
regexp = '/abc(.*?)efg/'; // (.*) matched hier enkel 'd' in de string

[ Voor 59% gewijzigd door crisp op 02-02-2004 22:05 ]

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Joen
  • Registratie: Juli 2003
  • Laatst online: 09-08 18:34
Owk, vooral die greedy en ungreedy match gata me een beetje het petje te boven, maar voor de rest een helder verhaal...

Vooral die links zijn goed, had ze zelf nog niet eerder ontdekt op de PHP site zelf :P

Maar als ik het goed begrijp kan ik op de plek waar ik zelf de vraagteken heb staan ook {0,1} in plaats van het vraagteken gebruiken?

Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

JeroenM_tbs schreef op 02 februari 2004 @ 22:15:
[...]
Maar als ik het goed begrijp kan ik op de plek waar ik zelf de vraagteken heb staan ook {0,1} in plaats van het vraagteken gebruiken?
Inderdaad, dat is equivalent, dus in plaatst van \"? kan je ook \"{0,1} schrijven, maar het vraagteken is natuurlijk korter :P
Dit geldt natuurlijk niet als je het vraagteken gebruikt om een quantifier ungreedy te maken.

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Justice
  • Registratie: Maart 2001
  • Laatst online: 07-08 15:02
- (.*?) vangt weer een bereik op van 0 of meer karakters
Ik probeer deze regel te begrijpen, maar wat is het verschil tussen
(.*?)
(.*)

Want hoe kan je nul of 1 keer een onbeperkt aantal willekeurige tekens pakken? Als het niet uitmaakt wat je pakt (immers je vangt < en > al af) dan kan je toch gewoon (.*) gebruiken?

Human Bobby


Acties:
  • 0 Henk 'm!

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09 23:18

djc

De ? maakt de .* ungreedy. Oftewel, hij probeert de match zo klein mogelijk te maken (zonder ? zou de match zo lang mogelijk worden).

floppybollieo
o(.*?)o -> ppyb, llie
o(.*)o -> ppybollie

Overigens vindt niet iedereen .* een nette oplossing.

[ Voor 3% gewijzigd door djc op 02-02-2004 22:42 ]

Rustacean


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Manuzhai schreef op 02 februari 2004 @ 22:41:
[...]
Overigens vindt niet iedereen .* een nette oplossing.
.* kan in veel gevallen gewoon wel een goede oplossing zijn, er zijn echter gevallen waarbij het inderdaad niet het gewenste resultaat oplevert en je dus beter een negated class kan gebruiken (hell, JS 1.3 kent ook geen ungreedy modifier dus dan moet je wel) eventueel met non-backrefs; echter vond ik dat te ver gaan om hier op in te gaan, dan had ik ook look-behind, look-ahead enzo moeten gaan uitleggen :P

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09 23:18

djc

crisp schreef op 02 februari 2004 @ 23:37:
.* kan in veel gevallen gewoon wel een goede oplossing zijn, er zijn echter gevallen waarbij het inderdaad niet het gewenste resultaat oplevert en je dus beter een negated class kan gebruiken (hell, JS 1.3 kent ook geen ungreedy modifier dus dan moet je wel) eventueel met non-backrefs; echter vond ik dat te ver gaan om hier op in te gaan, dan had ik ook look-behind, look-ahead enzo moeten gaan uitleggen :P
Ik gebruik het zelf ook voortdurend en kan me voorstellen dat je het niet allemaal wil uitleggen, maar dat artikeltje was ik kortgeleden tegengekomen en het leek me wel nuttig om dat even te delen hier. :)

Rustacean


Acties:
  • 0 Henk 'm!

  • vinnux
  • Registratie: Maart 2001
  • Niet online
Misschien handig om hier eens een mooie tutorial van op tweakers te zetten :D
Al misstaat de huidige FAQ niet, maar aanvulling is nooit weg.

[ Voor 30% gewijzigd door vinnux op 02-02-2004 23:50 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Manuzhai schreef op 02 februari 2004 @ 23:45:
[...]
Ik gebruik het zelf ook voortdurend en kan me voorstellen dat je het niet allemaal wil uitleggen, maar dat artikeltje was ik kortgeleden tegengekomen en het leek me wel nuttig om dat even te delen hier. :)
Het gaat wat ver voor iemand die net z'n eerste schreden zet bij het werken met reguliere expressies; het is een interessant artikel en geeft inderdaad goed weer waar je tegenaan kan lopen. Ikzelf ben daar ook ooit tegenaan gelopen en heb het toen ook met negated classes opgelost. Op zich blijft het allemaal heel logisch wat er gebeurd, maar een reguliere expressie moet je eigenlijk zien als een soort mini-programmaatje waar meestal nog wel wat bugs inzitten.

Uiteindelijk lijken regexpen heel verleidelijk vanwege de kracht, maar toch moet je er voor oppassen; je krijgt snel de neiging om het 'eventjes met een regexp' op te lossen terwijl andere manieren (string-functies bijvoorbeeld) vaak sneller zijn. Op het moment dat je regexp meer dan pak'mbeet 30 karakters lang wordt is het vaak slimmer om het in delen op te gaan splitsen, of combinaties van stringfuncties en reguliere expressies te gebruiken. Het feit dat je in JS een functie als replacement kan opgeven, en in PHP de e-modifier hebt of _callback kan gebruiken moet je dan zeker niet onbenut laten.

Ik heb nog wel wat leuke trouwens:

JavaScript:
1
var re = /([a-z]*)(\d*)(,?)(\d*)/g

deze is heel leuk omdat het feitelijk ook op een lege string matched omdat alle quantifiers ook matchen op 0 karakters; da's niet handig in een loop en je wacht totdat er null uitkomt. IE geeft trouwens op een gegeven moment well null terug, maar Mozilla blijft met een lege string als match komen aan het eind van de input :)

PHP:
1
$content = preg_replace_callback('/\[quote]((([^[]|\\[(?!\/?quote))*|(?R))*)\\[\/quote]/is', 'quote', $content);

recursie binnen een regexp met een callback :)

JavaScript:
1
2
var regExpr = new RegExp('(<\/[^<>]+>|<[^<>]+\/>|<(link|meta)[^<>]+>|<[^<>]+>(<\/[^<>]+>)?|[^<]+)', 'gi');
strString = strString.replace(regExpr, function($1) { return indent($1); });

hoe selecteer ik een tag in een html-string? :P

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

vgouw schreef op 02 februari 2004 @ 23:49:
Misschien handig om hier eens een mooie tutorial van op tweakers te zetten :D
Al misstaat de huidige FAQ niet, maar aanvulling is nooit weg.
Voor W&G ben ik nog steeds van plan een stuk te schrijven over het gebruik van reguliere expressies in javascript als aanvulling op het stuk in de P&W FAQ (die dus ook op JS van toepassing is). Daarin wil ik ook wel wat 'advanced' voorbeelden opnemen.
Helaas kent JS geen lookbehind en recursie binnen regexps, maar wel lookahead, non-capturing parentheses en best of all: gebruik van functies als replacement argument (iets wat ik in de praktijk eigenlijk nog nooit ben tegengekomen, maar wel heel handig is) :)

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
crisp schreef op 03 februari 2004 @ 00:08:
recursie binnen een regexp met een callback :)
Zou je dan ondertussen niet eens een reguliere grammatica gaan dicteren en vanuit daar een parser laten generen. Dan snap je het over een week ook nog. :o
Perl 6 gaat trouwens meer richting die kant ipv de regexes nog cryptischer te maken :) http://forum.javahova.net/topic.php?id=637

[ Voor 20% gewijzigd door Glimi op 03-02-2004 00:25 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:44

crisp

Devver

Pixelated

Glimi schreef op 03 februari 2004 @ 00:22:
[...]

Zou je dan ondertussen niet eens een reguliere grammatica gaan dicteren en vanuit daar een parser laten generen. Dan snap je het over een week ook nog. :o
Perl 6 gaat trouwens meer richting die kant ipv de regexes nog cryptischer te maken :) http://forum.javahova.net/topic.php?id=637
Dat is een kwestie van gewenning, geloof me; ik snap 'm in ieder geval nog steeds ;)
Ik heb geen diepgaande kennis van Perl, maar af en toe kijk ik wel eens in de perl-documentatie als het om reguliere expressies gaat, en vaak genoeg denk ik dan "damn, waarom zit dat nog niet in de PHP of JS regexp lib?".
PHP is wel redelijk ver qua regexp ondersteuning, maar heeft zo zijn eigen eigenaardigheden. JS is meer strict qua perl-syntax, maar mist dus nog veel features. De ungreedy-modifier en lookahead is in JS trouwens ook pas in versie 1.5 gekomen...

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Glimi
  • Registratie: Augustus 2000
  • Niet online

Glimi

Designer Drugs

(overleden)
crisp schreef op 03 februari 2004 @ 00:38:
Dat is een kwestie van gewenning, geloof me; ik snap 'm in ieder geval nog steeds ;)
Sorry hoor, maar dat is hetzelfde als aangeven dat de self-describing capacity net zo hoog is als die van C, als je er maar eenmaal aan went. Natuurlijk zijn *, + en ? zijn wel zodanig ingeburgerd, dat het 1-2-3 te begrijpen is, maar /s /g?
Ik zou zelf liever voor de volgende context vrije grammatica kiezen:
code:
1
2
3
4
5
[norml]
QUOTE -> "[quote]" WSPACE? TEKST? QUOTE? TEKST? WSPACE? "[/quote]"
QUOTE -> "" // epsilon
TEKST -> String
[/norml]

Kortom, een quote is een text tussen "[quote]" en "[/quote]" en daarin mag ook nog een quote zelf voorkomen, tot oneindige diepte.

[ Voor 16% gewijzigd door Glimi op 03-02-2004 10:16 ]


Acties:
  • 0 Henk 'm!

  • djc
  • Registratie: December 2001
  • Laatst online: 08-09 23:18

djc

crisp schreef op 03 februari 2004 @ 00:08:
Uiteindelijk lijken regexpen heel verleidelijk vanwege de kracht, maar toch moet je er voor oppassen; je krijgt snel de neiging om het 'eventjes met een regexp' op te lossen terwijl andere manieren (string-functies bijvoorbeeld) vaak sneller zijn. Op het moment dat je regexp meer dan pak'mbeet 30 karakters lang wordt is het vaak slimmer om het in delen op te gaan splitsen, of combinaties van stringfuncties en reguliere expressies te gebruiken. Het feit dat je in JS een functie als replacement kan opgeven, en in PHP de e-modifier hebt of _callback kan gebruiken moet je dan zeker niet onbenut laten.
Ik heb zelf dan ook eerder de neiging naar substr() en explode() te grijpen dan naar de pregs, maar voor bijvoorbeeld het scrapen van HTML om een trackertje te bouwen is een simpele regex als !<a class="news" href="(.*?)">(.*?)</a>!i toch wel erg nuttig.

Rustacean

Pagina: 1