[PHP/REGEX] Regex - herhaaldelijk patroon matchen

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
Ik breek mijn hoofd nu al TE lang gewoon over reguliere expressies in PHP.

Patroon:
code:
1
^select\s((?:,?\s*(?:(\w+)\.(\w+)))*)\s+from((?:,?\s*(\w+)(?:\s+(?:as\s+)?(\w+))?)*)


Te matchen tekst:
code:
1
select tbc1.col1, tbc1.col2, tbc2.col1 from table1, table2 t2, table3 as t3


Wat ik wil is het volgende:
De kolommen mét tabel prefix en de tabellen met evt aliassen (en evt as)

PHP kan deze reguliere expressie niet goed aan op de een of andere manier en krijg ik dit als resultaat:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Array
(
    [0] => Array
        (
            [0] => select tbc1.col1, tbc1.col2, tbc2.col1 from table1, table2 t2, table3 as t3
        )

    [1] => Array
        (
            [0] => tbc1.col1, tbc1.col2, tbc2.col1
        )

    [2] => Array
        (
            [0] => tbc2
        )

    [3] => Array
        (
            [0] => col1
        )

    [4] => Array
        (
            [0] =>  table1, table2 t2, table3 as t3
        )

    [5] => Array
        (
            [0] => table3
        )

    [6] => Array
        (
            [0] => t3
        )

)


Echter, als ik "The Regulator" gebruik, die ontwikkeld is in .NET krijg ik precies wat ik verwacht van de reguliere expressie waarbij array 2, 3, 5 en 6 het volgende bevat:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[2] => Array
        (
            [0] => tbc1
            [1] => tbc1
            [2] => tbc2
        )

    [3] => Array
        (
            [0] => col1
            [1] => col2
            [2] => col1
        )

    [5] => Array
        (
            [0] => table1
            [1] => table2
            [2] => table3
        )

    [6] => Array
        (
            [0] => t2
            [1] => t3
        )


Dus, wat is er mis met mijn regex zodat ik het beoogde resultaat krijg? Ik ben HOPELOOS!

321X


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Waarom een regex? k zou dit doen met een zooitje explodes, trims en strpos-en, hoef je je hoofd helemaal niet te breken over regexes.

Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
Cartman! schreef op vrijdag 20 november 2009 @ 22:18:
Waarom een regex? k zou dit doen met een zooitje explodes, trims en strpos-en, hoef je je hoofd helemaal niet te breken over regexes.
De volgende fase is dat ik de joins erbij wil hebben en er zijn veel mogelijke manieren om een join toe te passen...

321X


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Eerste wat dan nu bij me opkomt: wat wil je doen met die gegevens dan :?

Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
Cartman! schreef op vrijdag 20 november 2009 @ 22:30:
Eerste wat dan nu bij me opkomt: wat wil je doen met die gegevens dan :?
Een query analyzer schrijven die dynamisch het resultaat verwerkt in de gerelateerde objecten.

De tabel namen map ik op objecten en vul zodanig een object pool die ik kan verwerken in een template.

321X


Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:27

Creepy

Tactical Espionage Splatterer

Je wilt dus een SQL query parsen en daarna nog analyseren? Waarom dan een regexp gebruiken? Dat gaat echt niet voldoende zijn, laat staan leesbaar en onderhoudbaar. Heb je ooit al eens met een parser generator o.i.d. gewerkt? Ik krijg het gevoel dat je de complexiteit van het parsen van SQL namelijk behoorlijk onderschat.

[ Voor 4% gewijzigd door Creepy op 21-11-2009 10:53 ]

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
Creepy schreef op zaterdag 21 november 2009 @ 10:53:
Je wilt dus een SQL query parsen en daarna nog analyseren? Waarom dan een regexp gebruiken? Dat gaat echt niet voldoende zijn, laat staan leesbaar en onderhoudbaar. Heb je ooit al eens met een parser generator o.i.d. gewerkt? Ik krijg het gevoel dat je de complexiteit van het parsen van SQL namelijk behoorlijk onderschat.
Complexiteit van het parsen...

Het idee wat ik wil is niet echt complex, namelijk de kolommen welke worden geselect, de tabellen in de from en de tabel namen achter een join 'tag'... that's it.

Daarna, als ik dat heb, kan ik bepalen welke kolommen uit de records in welke objecten horen.

Een parser generator in de zin van een query builder heb ik ook aan gedacht, maar denk dat dit het er ook niet beter op maakt. Ik was hier zelfs al aan begonnen maar dat gaat imo ook een draak van een ding worden.

321X


Acties:
  • 0 Henk 'm!

  • XiniX88
  • Registratie: December 2006
  • Laatst online: 19:30
Als je je query nou op de volgende manier opslaat:

PHP:
1
2
3
4
5
6
$array = array(
    'sort' => 'select', 
    'columns' => array('bla.bla1', 'bla.bla2'), 
    'from' => array('name' => 'tabelnaam', 'as' => 'nieuwe naam'), 
    'leftJoin' => array('name' => 'tabelnaam', 'as' => 'nieuwe naam'), 
    'where' => ...);


of in een soortgelijk object, kan je het analyseren, queries erop los gooien... en hoef je niet te regexxen.

Wat jij zegt gaat namelijk heel moeilijk, de volgorde van sommige dingen kan verschillen, en in 1 regex zou je niet alle colommen ook kunnen scheiden.

Met objecten zou je zoiets kunnen doen:
PHP:
1
2
3
4
5
6
class selectQuery {
    function set($array){ // verwerkt bovenstaande array b.v.
    }
    function setFrom($from){}
    function setWhere($where){}
}


Ik haat in vele gevallen alleen bovenstaande manier, het kost zoveel typwerk (tis wel netter). Mooie hiervan is dat je het ook nog eens gemakkelijk naar andere databases kan porten... SQL92 standaard werkt helaas niet voor elke query.

[ Voor 48% gewijzigd door XiniX88 op 21-11-2009 13:25 ]


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
Zelfs met de joins blijf ik erbij dat je nog steeds beter kunt blijven bij explodes en strpos om te vinden wat je nodig hebt. Echter zou ik zelf eerder kiezen voor de bovenstaande optie en met een querybuilder aan de gang gaan (discussie hierover wil ik niet starten, hebben we t laatst over gehad...) want dan kun je makkelijker wat je wilt.

Andere vraag: waarom kijk je niet eens naar Doctrine? Die doet volgens mij wat jij probeert te bereiken... (zover ik dat kan inschatten adhv. dit topic).

Acties:
  • 0 Henk 'm!

  • CMG
  • Registratie: Februari 2002
  • Laatst online: 10-12-2024

CMG

Voor de kolommen zou je zo iets kunnen doen:
SELECT[\r\n\t\s]+(((\[(?<table>[^\]]+)\]\.)|(?<table>[^.\s]+)\.){0,1}((\[(?<col>[^\]]+)\])|(?<col>[^.\s,]+))[\r\n\t\s,]+)FROM
getest met:
select tbc1.col1, tbc1.col2, tbc2.col1, tbc2.[mijn col met spaties], col435 from table1, table2 t2, table3 as t3
Een andere optie zou zijn om je query in stukken de delen eerst

Dus: eerst columns oppakken met: "SELECT[\r\n\t\s]+(?<cols>.*?)FROM"
zelfde voor je tabellen lijst, joins, order by, where, etc.

Dan een enkel patroon voor een herhaling pakken en zo je array ophalen van dat onderdeel.

[ Voor 30% gewijzigd door CMG op 21-11-2009 19:10 ]

NKCSS - Projects - YouTube


Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
CMG schreef op zaterdag 21 november 2009 @ 19:07:
Voor de kolommen zou je zo iets kunnen doen:

[...]

getest met:


[...]


Een andere optie zou zijn om je query in stukken de delen eerst

Dus: eerst columns oppakken met: "SELECT[\r\n\t\s]+(?<cols>.*?)FROM"
zelfde voor je tabellen lijst, joins, order by, where, etc.

Dan een enkel patroon voor een herhaling pakken en zo je array ophalen van dat onderdeel.
Ja, ik denk dat ik zoiets ga toepassen... blijft het ook nog leesbaar ook.

@cartman:
Doctrine ken ik niet, Hibernate wel. Is óók een optie denk ik... maar ik vind het leuk om zelf te ontwikkelen + dat ik dan weet welke code/functies er gebruikt worden en op zo'n manier denk ik effectiever kan programmeren. Thanks!

321X


Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
XiniX88 schreef op zaterdag 21 november 2009 @ 13:14:
Als je je query nou op de volgende manier opslaat:

PHP:
1
2
3
4
5
6
$array = array(
    'sort' => 'select', 
    'columns' => array('bla.bla1', 'bla.bla2'), 
    'from' => array('name' => 'tabelnaam', 'as' => 'nieuwe naam'), 
    'leftJoin' => array('name' => 'tabelnaam', 'as' => 'nieuwe naam'), 
    'where' => ...);


of in een soortgelijk object, kan je het analyseren, queries erop los gooien... en hoef je niet te regexxen.

Wat jij zegt gaat namelijk heel moeilijk, de volgorde van sommige dingen kan verschillen, en in 1 regex zou je niet alle colommen ook kunnen scheiden.

Met objecten zou je zoiets kunnen doen:
PHP:
1
2
3
4
5
6
class selectQuery {
    function set($array){ // verwerkt bovenstaande array b.v.
    }
    function setFrom($from){}
    function setWhere($where){}
}


Ik haat in vele gevallen alleen bovenstaande manier, het kost zoveel typwerk (tis wel netter). Mooie hiervan is dat je het ook nog eens gemakkelijk naar andere databases kan porten... SQL92 standaard werkt helaas niet voor elke query.
Ja, hier was ik ook aan begonnen maar toen toch niet doorgezet omdat ik dit behoorlijk omslachtig vind en met sommige complexe parameterized queries loopt deze principe denk ik vast (tenzij je nog omslachtiger gaat werken). Het kost veel tijd om een query op te stellen. Maar je hebt helemaal gelijk over dat het netter is.

321X


Acties:
  • 0 Henk 'm!

  • Cartman!
  • Registratie: April 2000
  • Niet online
321X schreef op zaterdag 21 november 2009 @ 22:39:
[...]
@cartman:
Doctrine ken ik niet, Hibernate wel. Is óók een optie denk ik... maar ik vind het leuk om zelf te ontwikkelen + dat ik dan weet welke code/functies er gebruikt worden en op zo'n manier denk ik effectiever kan programmeren. Thanks!
Be my guest, beter dan een heel team die er al jaren aan werken ga je het toch niet maken ;) Maar veel succes gewenst bij deze :)

Acties:
  • 0 Henk 'm!

  • b19a
  • Registratie: September 2002
  • Niet online
Ik ben bezig nagenoeg hetzelfde te bouwen. Hetzelfde resultaat, maar een andere aanpak middels mysql_field_table. Aannemende dat elk object een eigen tabel heeft, kun je die middels de beschreven code in mijn blogpost uitsorteren.

Acties:
  • 0 Henk 'm!

  • 321X
  • Registratie: April 2009
  • Laatst online: 01-01-2023
BoukeHaarsma schreef op zondag 22 november 2009 @ 16:06:
Ik ben bezig nagenoeg hetzelfde te bouwen. Hetzelfde resultaat, maar een andere aanpak middels mysql_field_table. Aannemende dat elk object een eigen tabel heeft, kun je die middels de beschreven code in mijn blogpost uitsorteren.
Ja, elk object is een representatie van een tabel. Ik zal eens even kijken.

-- Edit --
Dat is precies wat ik zoek :D Alleen ... is dit ook mogelijk met mysqli ? Zojuist de PHP manual ff doorzocht maar kan ff niks vinden. Suggesties?

Ah! http://nl2.php.net/manual/en/mysqli-result.fetch-field.php Ik ben blij! Iedereen bedankt.

[ Voor 19% gewijzigd door 321X op 22-11-2009 20:55 ]

321X

Pagina: 1