[PHP/Reg.Exps] Meerdere herhalingen, slaat alleen laatste op

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • R_W
  • Registratie: Oktober 2002
  • Niet online
Ik probeer een IF/ELSEIF/ELSE statement te parsen.

Dit doe ik met de volgende Regular Expression:

code:
1
/\\[IF ([-a-z0-9_]+)=\"[-a-z0-9\.\/_]+\"\](.+?)(\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*(\\[ELSE\](.+?))?\\[\/IF \\1\]/si


code:
1
(\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*


Betekent dus dat er 0 of meer ELSEIF's kunnen voorkomen. Deze worden dan opgeslagen in \\3.

Het probleem is nu dat als er meerdere ELSEIF's zijn, alleen de laatste ELSEIF in \\3 wordt opgeslagen. Ik heb dit getest met een preg_replace( $regExp, $source, $match ); en vervolgens print_r( $match ). Op php.net staat daar het volgende over:
When a capturing subpattern is repeated, the value captured is the substring that matched the final iteration.
Maar het is voor mij natuurlijk belangrijk dat ik ze allemaal (apart) krijg.

De manual bood voor zover ik gezien heb, hiervoor geen oplossing.

Wie wel?

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Als je nou eens eerst een regexp maakt die een array van alle if/elseif/else statements in zijn geheel teruggeeft, en vervolgens in elk element van die array kijkt, dan ben je toch klaar?

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • R_W
  • Registratie: Oktober 2002
  • Niet online
Dat is juist het probleem, ik krijg een array waar alleen de laatste ELSEIF instaat.

Tenzij je het op een andere manier wilt doen? Kun je daar dan een vb. van geven? :)

Acties:
  • 0 Henk 'm!

  • avoid
  • Registratie: November 2002
  • Laatst online: 15:53
Kijk eens naar preg_match_all....
http://nl3.php.net/preg_match_all

Time flies like an arrow, fruit flies like a banana.


Acties:
  • 0 Henk 'm!

  • R_W
  • Registratie: Oktober 2002
  • Niet online
Zelfde probleem...

Dat had ik natuurlijk al geprobeerd.

[ Voor 53% gewijzigd door R_W op 02-07-2004 17:08 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Als jij nou een preg_match_all doet op de gehele tekst waardoor je een array terug krijgt met alle gehele IF constructies.... Dan kun je daar weer een match doen op alle elseifs daarbinnen. En die kun je dan weer in een array.

Verder is voor een source code parser, wat jij nu blijkbaar maakt, een eigen (stackbased?) parser vaak beter.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

De repetition * wordt niet gecaptured omdat hij in een group staat:
code:
1
(\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*

moet dan worden
code:
1
((?:\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*)
zodat alle ELSEIF's in 1 group komen te staan, namelijk \3. Het nadeel is echter wel dat je die alsnog moet matchen op de afzonderlijke ELSEIF's. Wat jij wilt is feitelijk een tweedimensionale match-array gemixt met een 1 dimensionale; resp. preg_match_all en preg_match inéén, en dat gaat helaas niet. Het is of het één of het ander, en in dit geval zul je het in twee stappen moeten doen.

bekend probleem; jammer maar helaas :)

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


Acties:
  • 0 Henk 'm!

  • R_W
  • Registratie: Oktober 2002
  • Niet online
Nou, als je dan zo'n geheel IF statement neemt. En binnen dat ene IF-statement staan meerdere ELSEIF's, dan heb je nog steeds hetzelfde probleem hoor :?

En ik ben inderdaad een (template-)parser aan het maken, maar dat doet er niet echt toe lijkt me.

Acties:
  • 0 Henk 'm!

Verwijderd

Dit probleem kan je niet in één stap oplossen omdat je match array ook daadwerkelijk met je haakjes moet matchen ;) Wat ik in jouw geval zou doen is de IF, ELSE en de complete groep ELSEIFs matchen en dan vervolgens met preg_match_all de ELSEIFs weer los matchen iets als dit dus:

PHP:
1
2
3
4
5
6
7
8
$regexp1 = '/\\[IF ([-a-z0-9_]+)=\"[-a-z0-9\.\/_]+\"\](.+?)((\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*)(\\[ELSE\](.+?))?\\[\/IF \\1\]/si';
$regexp2 = '/(\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))/si';

preg_match($regexp1, $code, $matches);

if (!empty($matches[3])) {
    preg_match_all($regexp2, $matches[3], $matchesElseif);
}

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 02:21

Janoz

Moderator Devschuur®

!litemod

Waarom gebruik je geen stackbased parser? Die wordt waarschijnlijk een heel stuk sneller.

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


Acties:
  • 0 Henk 'm!

  • R_W
  • Registratie: Oktober 2002
  • Niet online
drm schreef op 02 juli 2004 @ 17:12:
De repetition * wordt niet gecaptured omdat hij in een group staat:
code:
1
(\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*

moet dan worden
code:
1
((?:\\[ELSEIF \\1=\"[-a-z0-9\.\/_]+\"\](.+?))*)
zodat alle ELSEIF's in 1 group komen te staan, namelijk \3. Het nadeel is echter wel dat je die alsnog moet matchen op de afzonderlijke ELSEIF's. Wat jij wilt is feitelijk een tweedimensionale match-array gemixt met een 1 dimensionale; resp. preg_match_all en preg_match inéén, en dat gaat helaas niet. Het is of het één of het ander, en in dit geval zul je het in twee stappen moeten doen.

bekend probleem; jammer maar helaas :)
Aha, kijk het is dus niet mogelijk. Das wel handig om te weten ;)

Heb ik nog 1 vraagje, die '?:' wat doet die daar?

Acties:
  • 0 Henk 'm!

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06 13:31

drm

f0pc0dert

Heb ik nog 1 vraagje, die '?:' wat doet die daar?
?: zorgt voor een non-captured group. Dus een groepering die je naderhand niet perse wilt matchen capturen/gebruiken. Dat is meestal wenselijk om je match-array zuiver te houden. Als je hem in dit geval wel zou laten matchencapturen, krijg je alleen maar de laatste ELSEIF in \4, en daar heb je toch niks aan. Good practice dus :)

edit:
beetje duidelijker

[ Voor 9% gewijzigd door drm op 02-07-2004 17:24 ]

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz

Pagina: 1