U bevindt zich hier: Forum » Tutorials » [PHP] Reguliere expressies
   Actief Topic: [PHP] Reguliere expressies

Vorige ( 1 ) Volgende

vlerknozem
Admin
avatar
# Gepost op 18-08-2009 23:27
Bewerkt door vlerknozem op 19-08-2009 00:49


Reguliere expressies, beter bekend als RegEx worden regelmatig gebruikt. Met een stukje tekst (pattern) kan je bepaalde delen van een string verwijderen of veranderen. Het handige is dat de pattern syntax over het algemeen bij alle programmeertalen hetzelfde is. Maar de zaak erom heen, hoe je die pattern kan gebruiken, verschilt dan wel weer. Ik ga me nu bezighouden met php.

We gaan eerst simpel beginnen. We maken een string, en controleren of het woord 'noot' in de string voorkomt. In dit geval is het hoofdlettergevoelig.

Plain | Plain new window | PHP code:
  1. <?php
  2. // Onze string
  3. $string = 'aapnootmies';
  4.  
  5. if(preg_match('/noot/', $string)) {
  6.     echo "Het woord noot komt voor in de string.";
  7. } else {
  8.     echo "Het woord noot is niet gevonden.";
  9. }
  10. ?>


Nu willen we zorgen dat het niet meer hoofdletter gevoelig is. Dit kan met een i achter de '/'.

Plain | Plain new window | PHP code:
  1. <?php
  2. // Onze string
  3. $string = 'aapNOOTmies';
  4.  
  5. if(preg_match('/noot/i', $string)) {
  6.     echo "Het woord noot komt voor in de string.";
  7. } else {
  8.     echo "Het woord noot is niet gevonden.";
  9. }
  10. ?>

In dit geval zal hij 'NOOT' toch vinden. Als we in het vorige voorbeeld 'noot' met hoofdletters hadden geschreven, dan zouden we geen match hebben.
Nu willen we kijken of het woord 'aap' aan het begin van de string staat. Om het voor mij makkelijker te maken, ga ik nu niet meer steeds een if structuur eromheen zetten. Als er een match is zal preg_match de waarde 1 returen. Bij geen match is het dus 0.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_match('/^aap/', 'aapnootmies'); // Een match
  3. echo preg_match('/^aap/', 'aaapnootmies'); // Geen match
  4. // Je zal dus nu zien: 10
  5. ?>


Als we willen controleren of aap aan het einde van de string staat:
Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_match('/aap$/', 'nootmiesaap'); // Een match
  3. echo preg_match('/aap$/', 'nootmiesaapp'); // Geen match
  4. echo preg_match('/aap$/', 'aapnootmies'); // Geen match
  5. // Je zal dus nu zien: 100
  6. ?>


Als je nu even nadenkt dan zou je nu ook moeten weten hoe je controlleert op een woord alleen in de string staat.
Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_match('/^aap$/', 'aap'); // Een match
  3. echo preg_match('/^aap$/', 'aaap'); // Geen match
  4. echo preg_match('/^aap$/', 'aapnootmies'); // Geen match
  5. ?>


Nu gaan we het wat ingewikkelder maken. Stel wel willen met een pattern checken of het woord een van de woorden 'bal', 'bol', 'bil' is. Dit doen we met karaktersets. Hiervoor worden de tekens '[' en ']' gebruikt.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_match('/^b[aoi]l$/', 'bal'); // Een match
  3. echo preg_match('/^b[aoi]l$/', 'bil'); // Een match
  4. echo preg_match('/^b[aoi]l$/', 'bel'); // Geen match
  5. echo preg_match('/^b[aoi]l$/', 'voetbal'); // Geen match
  6. ?>


Bovenstaand voorbeeld wordt het woord 'voetbal' niet gematched. Waarom niet? Omdat 'bal' wel op het einde, maar niet op het begin van de string staat. Hier ga ik verder niet meer op in, omdat ik dit eerder al heb uitgelegd. Maar we kunnen meer met die karaktersets. In het volgende voorbeeld wil ik alles dat begint met een b en eindig op l gaan vervangen door vis.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/b[a-z]l/', 'vis', 'ballon'); // In dit geval wordt ballon vervangen door vislon
  3. echo preg_replace('/b[a-z]l/', 'vis', 'billgates'); // vislgates
  4. echo preg_replace('/b[a-z]l/', 'vis', 'banaan'); // Geen match, dus er wordt niks vervangen.
  5. ?>


Maar nu gaan we hetzelfde doen, maar dan met meerdere karakters. Het teken \ gebruiken we om karakters die ook door regex zelf worden gebruikt te escapen. Doen we dit niet dan zal er een fout optreden.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/b[a-z0-9_\-]l/', 'vis', 'b4llon'); // In dit geval wordt b4llon vervangen door vislon
  3. echo preg_replace('/b[a-z0-9_\-]l/', 'vis', 'b_llgates'); // vislgates
  4. echo preg_replace('/b[a-z0-9_\-]l/', 'vis', 'b9l'); // vis
  5. echo preg_replace('/b[a-z0-9_\-]l/', 'vis', 'b99l'); // Geen match
  6. ?>


In bovenstaand voorbeeld zie je dat 'b99l' dus niet wordt vervangen. Waarom? Omdat er minimaal 1, en maximaal 1 karakter voorkomt tussen de 'b' en de 'l'. Nu willen we dus we dus ook een resultaat hebben als er geen karakter is, en als er meerdere karakters zijn tussen de b en de l. Hiervoor gebruiken we meta-karakters.

? Matched 0 of 1 karakter uit het karakterset
+ Matched 1 of meer karakter uit het karakterset
. Matched meer dan 1 karakter uit het karakterset

Dit gaan we in praktijk brengen met hetvolgende voorbeeld:
Plain | Plain new window | PHP code:
  1. <?php
  2. // Met een '?'
  3. echo preg_replace('/b[a-z0-9_\-]?l/', 'vis', 'bal'); // bal wordt vervangen door vis
  4. echo preg_replace('/b[a-z0-9_\-]?l/', 'vis', 'bl'); // bl wordt vervangen door vis
  5. echo preg_replace('/b[a-z0-9_\-]?l/', 'vis', 'baal'); // Geen match
  6.  
  7. // Met een '+'
  8. echo preg_replace('/b[a-z0-9_\-]+l/', 'vis', 'bal'); // bal wordt vervangen door vis
  9. echo preg_replace('/b[a-z0-9_\-]+l/', 'vis', 'bl'); // Geen match
  10. echo preg_replace('/b[a-z0-9_\-]+l/', 'vis', 'baal'); // baal wordt vervangen door vis*/
  11.  
  12. // Met een '.'
  13. echo preg_replace('/b[a-z0-9_\-].l/', 'vis', 'bal'); // Geen match
  14. echo preg_replace('/b[a-z0-9_\-].l/', 'vis', 'bl'); // Geen match
  15. echo preg_replace('/b[a-z0-9_\-].l/', 'vis', 'baal'); // baal wordt vervangen door vis
  16. ?>


Nu gaan we hetzelfde doen, maar dan even in een gewone string, zonder karaktersets:
Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/ph*p/', 'html', 'php'); // html
  3. echo preg_replace('/ph.p/', 'html', 'php'); // php
  4. echo preg_replace('/ph.p/', 'html', 'phhp'); // html
  5. echo preg_replace('/ph?p/', 'html', 'php'); // html
  6. ?>


Maar nu willen we het aantal karakters zelf aangeven in cijfers. Hiervoor gebruiken we de tekens '{' en '}'.

{0,2} 0 tot 2
{2,} 2 of meer
{1,2} 1 of 2

De pattern /ph{0,2}p/ matched dus pp, php en phhp. Maar niet phhhp, phhhhp, enzovoorts.
De pattern /ph{2,}p/ matched dus phhp, phhhp, enzovoorts. Maar niet php of pp.

Uitgebreid aanpassen van strings
We gaan nu gebruik maken van haakjes '(' en ')'. Ook gaan we gebruik maken van '*'. Stel we willen alles tussen [b] en [/b] tussen <b> en </b> zetten. Dit is handig voor een ubb parser.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/\[b\](.*?)\[\/b\]/', '<b>\\1</b>', '[b]bold[/b]');
  3. ?>

Wat betekend '.*?' nu precies? Het sterretje in '.*?' staat voor alle karakters. Dus dit kan een cijfer zijn, of een letter, maar ook andere tekens. De andere tekens heb ik eerder uitgelegd. De \\1 in de vervangende string zegt dat op die plek de gematchte tekst tussen de eerste haakjes moet komen. Ik geef even een voorbeeld met meer haakjes.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/([^a-z ]+)([^0-9]+)/i', '\\2, en is \\1 jaar geworden.', 'Een 33 jarige aap genaamd mies eet een noot');
  3. // Een jarige aap genaamd mies eet een noot, en is 33 jaar geworden.
  4. ?>

Het eerste deel ([^a-z ]+) matched alle letters en spaties, het tweede deel ([^0-9]+) matched alle cijfers.

Het ^ teken
Eerder zag je dat het ^ teken wordt gebruikt voor het matchen van iets aan het begin van de string. Maar zoals je ziet in het vorige voorbeeld, wordt het ook gebruikt om alle karakters die niet gelijk zijn aan iets te matchen. Wil je bijvoorbeeld ALLE tekens BEHALVE letters verwijderen, dan gebruik je:

Het | teken
Deze heb ik nog niet uitgelegd. Het betekend hetzelfde als 'of' (in het engels 'or').

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/banaan|appel/', 'fruitstuk', 'Een banaan of appel is lekker');
  3. // Een fruitstuk of fruitstuk is lekker
  4. ?>


Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/[^a-z]/i', '', 'ABCDEFGabcdefg123a45e*&z()F-+Q?'); // ABCDEFGabcdefgaezFQ
  3. ?>


Dit kan dus handig zijn om illegale karakters uit een bestandsnaam te wissen.

Speciale tekens
De backslash kan ook gebruikt worden voor andere zaken dan alleen escapen.

\d matched alle numerieke karakters, hetzelfde als [0-9]
\D matched alle niet nummerieke karakters, hetzelfde als [^0-9]
\s matched alle witruimte, hetzelfde als [ \t\n\r\f\v]
\S matched alle niet witruimte, hetzelfde als [^ \t\n\r\f\v]
\w matched alle alpha numerieke karakters, hetzelfde als [a-zA-Z0-9_]
\W matched alle niet alpha numerieke karakters, hetzelfde als [^a-zA-Z0-9_]


Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/\d/i', '', "ABCDEFGab   \t cdefg1  23a45e*  &z()F-+Q?");
  3. // 'ABCDEFGab        cdefg  ae*  &z()F-+Q?'
  4.  
  5. echo preg_replace('/\D/i', '', "ABCDEFGab   \t cdefg1  23a45e*  &z()F-+Q?");
  6. // '12345'
  7.  
  8. echo preg_replace('/\s/i', '', "ABCDEFGab   \t cdefg1  23a45e*  &z()F-+Q?");
  9. // 'ABCDEFGabcdefg123a45e*&z()F-+Q?'
  10.  
  11. echo preg_replace('/\S/i', '', "ABCDEFGab   \t cdefg1  23a45e*  &z()F-+Q?");
  12. // '         '
  13.  
  14. echo preg_replace('/\w/i', '', "ABCDEFGab   \t cdefg1  23a45e*  &z()F-+Q?");
  15. // '       *  &()-+?'
  16.  
  17. echo preg_replace('/\W/i', '', "ABCDEFGab   \t cdefg1  23a45e*  &z()F-+Q?");
  18. // 'ABCDEFGabcdefg123a45ezFQ'
  19. ?>


Controlleren of een email adres geldig is
Met bovenstaande uitleg zou je dus een simpele controlle kunnen doen.
Plain | Plain new window | PHP code:
  1. <?php
  2. if(preg_match('/[a-z]+@[a-z]+\.[a-z]+/', 'email@test.nl')) {
  3.     echo 'Geldig';
  4. } else {
  5.     echo 'Ongeldig';
  6. }
  7. ?>

Maar natuurlijk is dit nog niet helemaal goed. Er mogen meerdere tekens voorkomen, en het moet niet hoofdletter gevoelig zijn.

Plain | Plain new window | PHP code:
  1. <?php
  2. preg_match('/[a-z0-9_\-\.]+@[a-z0-9_\-\.]+\.[a-z]{0,3}/i', 'email@test.nl'); // geldig
  3. ?>


Omdat het nu ingewikkelder eruit ziet, zal ik even de delen uit elkaar halen.
[a-z0-9_\-\.]+ matched letters, cijfers en de tekens '_', '-', en '.'.
@ matched het apenstaartje in een email adres
[a-z0-9_\-\.]+ komt nog een keer voor.
\. matched de . in een email
[a-z]{0,3} matched de extensie (nl, com, org, etc).

Matches naar een array plaatsen
Met preg_match kan je de gematchte dingen naar een array plaatsen. Laten we eens kijken.

Plain | Plain new window | PHP code:
  1. <?php
  2. preg_match('/\[b\](.*?)\[\/b\]/', '[b]test[/b]', $matches);
  3. print_r($matches);
  4. ?>


Zal dus weergeven:

Plain | Plain new window | PHP code:
  1. (
  2.     [0] => [b]test[/b]
  3.     [1] => test
  4. )
  5.  


Nu even een vrij lastige
Ik geef nu een voorbeeld van een vrij ingewikkelde regexp. Het is de bedoeling dat $beker="kofie"; vervangen wordt door 'De beker is gevuld met koffie.'. Maar er mogen spaties in komen, de quotes mogen weg gelaten worden, en beker mag ook iets anders zijn, en koffie mag ook iets anders zijn.

Plain | Plain new window | PHP code:
  1. <?php
  2. echo preg_replace('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/i', 'De \\1 is gevuld met \\2.', '$beker = "koffie";');
  3. ?>

Lastig he? Goed ik probeer het iets te verklaren.

$beker matchen
\$ Deze matched dus de '$'.
([a-z]+) matched alleen letters.

Spaties tussen '$beker' en '=', en tussen '=' en '"' matchen
\s{0,} Matched 0 of meer spaties (of andere witruimte karakters).

De quotes
["|\']? matched 0 of 1 dubbele quote, of 0 of 1 enkele quote

De puntkomma
Het ';' matches vanzelfspreken het ';' teken, en sluit de variabele af.

Probeer nu voor de grap $beker eens te vervangen door $kan. Of vervang "koffie" eens door "thee".

Deze lastige nog een keer, maar dan met preg_match
De volgende code zal het zelfde weergeven als het vorige voorbeeld
Plain | Plain new window | PHP code:
  1. <?php
  2. preg_match('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/is', '$beker = "koffie";', $matches);
  3. echo 'De '.$matches[1].' is gevuld met '.$matches[2].'.';
  4. ?>


Maar wat nu als we meerdere variabelen willen gebruiken? Een voorbeeld:
Plain | Plain new window | PHP code:
  1. <?php
  2. preg_match('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/is', '$beker = "koffie";$kan = "thee";', $matches);
  3. print_r($matches);
  4. ?>


resulteert:

Plain | Plain new window | PHP code:
  1. (
  2.     [0] => $beker = "koffie";
  3.     [1] => beker
  4.     [2] => koffie
  5. )


Waar is dan die kan thee gebleven? Hiervoor kunnen we preg_match_all gebruiken.

Plain | Plain new window | PHP code:
  1. <?php
  2. preg_match_all('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/is', '$beker = "koffie";$kan = "thee";', $matches);
  3. print_r($matches);
  4. ?>


Resulteert:

Plain | Plain new window | PHP code:
  1. (
  2.     [0] => Array
  3.         (
  4.             [0] => $beker = "koffie";
  5.             [1] => $kan = "thee";
  6.         )
  7.  
  8.     [1] => Array
  9.         (
  10.             [0] => beker
  11.             [1] => kan
  12.         )
  13.  
  14.     [2] => Array
  15.         (
  16.             [0] => koffie
  17.             [1] => thee
  18.         )
  19.  
  20. )


Om deze gegevens nu te gebruiken, kunnen we bijvoorbeeld doen:

Plain | Plain new window | PHP code:
  1. <?php
  2. preg_match_all('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/is', '$beker = "koffie";$kan = "thee";', $matches);
  3. foreach($matches[0] as $key => $value) {
  4.     echo 'De '.$matches[1][$key].' is gevuld met '.$matches[2][$key].'.<br />';
  5. }
  6. ?>


En je ziet verschijnen:
  1. De beker is gevuld met koffie.
  2. De kan is gevuld met thee.


Een functie gebruiken om iets te doen met de matches
Het kan soms handig zijn om een functie te gebruiken om iets te doen met de matches. Ik gebruik hiervoor weer dezelfde regex. We gaan nu gebruik maken van preg_replace_callback.

Plain | Plain new window | PHP code:
  1. <?php
  2. preg_replace_callback('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/is', 'callback_functie', '$beker = "koffie";$kan = "thee";');
  3. function callback_functie($matches) {
  4.     echo 'De '.$matches[1].' is gevuld met '.$matches[2].'.<br />';
  5. }
  6. ?>

Dit heeft hetzelfde resultaat als het vorige voorbeeld. Bij OOP werkt dit iets anders. Op de plek van 'callback_functie' komt dan een array met $this erin, en de functie naam. Een klein voorbeeld:
Plain | Plain new window | PHP code:
  1. <?php
  2. class foo {
  3.     function bar() {
  4.         return preg_replace_callback('/\$([a-z]+)\s{0,}=\s{0,}["|\']?([a-z]+)["|\']?;/is', array($this, 'callback_functie'), '$beker = "koffie";$kan = "thee";');
  5.     }
  6.  
  7.     function callback_functie($matches) {
  8.         return 'De '.$matches[1].' is gevuld met '.$matches[2].'.<br />';
  9.     }
  10. }
  11. $foo = new foo();
  12. echo $foo->bar();
  13. ?>



Tot slot
Dit was erg veel. Ik raad aan om gewoon te experimenteren hiermee. En natuurlijk hoef je het niet in een keer uit je hoofd te weten, je kan altijd even terug kijken naar hoe het ook alweer zat. Wellicht dat ik de tutorial nog iets ga aanpassen om eventuele fouten te corrigeren, of dingen beter uit te leggen.

Succes!

Lees de forum regels

wesley
member
avatar
# Gepost op 19-08-2009 00:07


Reguliere expressies zijn best fijn. Leuke tutorial ook!

vlerknozem
Admin
avatar
# Gepost op 19-08-2009 00:52


Ik heb de tutorial nog iets uitgebreid :)

Lees de forum regels

TijmenD
member
avatar
# Gepost op 19-08-2009 00:55


Alsof het nog niet goed genoeg was :D

Hihi.

vlerknozem
Admin
avatar
# Gepost op 19-08-2009 06:06


Citaat van TijmenD
Alsof het nog niet goed genoeg was :D

Haha, grappig, die smiley trekt dezelfde bek als je chick :P

Ja het was eigenlijk wel genoeg, maar ik wilde toch nog een paar dingen erbij vertellen ;)

Lees de forum regels

TijmenD
member
avatar
# Gepost op 19-08-2009 11:42


Citaat van vlerknozem
Haha, grappig, die smiley trekt dezelfde bek als je chick

Zo lekker.

Hihi.

Vorige ( 1 ) Volgende

U moet aangemeld zijn om een reactie te kunnen plaatsen.

Indien u nog geen account heeft kunt u zich hier registreren.



© copyright 2009/2010 WebProjects 1.02 - Template van Sebastaan Franken