[PHP]Regex vraagstuk

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Kan iemand mij helpen met een regex probleem? Ik wil het volgende op kunnen halen

• int(9) unsigned
• varchar(30)
• text

Dus een regex moet drie verschillende dingen kunnen zien, nu zit ik al iets te spelen met lookahead, maar ik kom er niet uit.

De volgende match wel iets, maar alleen het eerste deel (int, of varchar) text match hij dan weer niet.
code:
1
'/([a-z]+)(?=\([0-9]+\))/'


Naar mijn weten is het mogelijk om met één regex patroon de volgende resultaten te krijgen:
  • Bij text -> een array met één resultaat, array('text')
  • Bij varchar(30) een array met twee resultaten, array('varchar', '30')
  • Bij int(9) unsigned een array met drie resultaten, array('int', '9', 'unsigned')

Acties:
  • 0 Henk 'm!

  • DataGhost
  • Registratie: Augustus 2003
  • Laatst online: 20:41

DataGhost

iPL dev

Kijk eens wat | doet. Verder is het misschien leuk wat meer achtergrondinformatie te geven over je probleem, eventuele voorbeelddata enzo? Daarnaast zal je het niet zo 1-op-1 in het formaat terugkrijgen wat jij laat zien maar het zal niet heel moeilijk te realiseren zijn.

Acties:
  • 0 Henk 'm!

  • Arjan
  • Registratie: Juni 2001
  • Niet online

Arjan

copyright is wrong

(int|varchar|text)(\(([0-9]+)\))?\s*(unsigned)? :?

in stukken:

(int|varchar|text) = een van deze woorden
(\(([0-9]+)\))? = een getal 0 <= oneindig tussen haakjes ( zonder whitespace btw )
\s* = optionele whitespace
(unsigned)? = optioneel de string unsigned


dit levert de volgende matches:
int(9) unsigned
0: int
1: (9)
2: 9
3: unsigned


varchar(30)
0: varchar
1: (30)
2: 30
3:


text
0: text
1:
2:
3:

[ Voor 3% gewijzigd door Arjan op 31-01-2012 23:01 ]

oprecht vertrouwen wordt nooit geschaad


Acties:
  • 0 Henk 'm!

  • pedorus
  • Registratie: Januari 2008
  • Niet online
Het makkelijkst lijkt me splitten op zowel '(' als ')' en ' '.
PHP:
1
print_r(preg_split("/[() ]/", "int(9) unsigned", 0 , PREG_SPLIT_NO_EMPTY))

Of misschien moet je even aangeven wat nu echt de bedoeling is ;)

Vitamine D tekorten in Nederland | Dodelijk coronaforum gesloten


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Ik hou er niet van zaken voorgekauwd en wel aan te leveren maar bekijk dit eens:
code:
1
int\([0-9]+\)\s(unsigned)?|varchar\([0-9]+\)|text


Dat vertaalt zich naar:
PHP:
1
2
3
4
5
6
7
8
9
10
$test = 'asdh int(9) unsigned qwee
        qeioh int(15) lohqwe
        dioqh epqio varchar(30) oiqwheopi
        weqg text pioqwe';

$matches = null;

preg_match_all('/int\([0-9]+\)(\sunsigned)?|varchar\([0-9]+\)|text/i' , $test, $matches);

var_dump($matches[0]);

array(4) {
  [0]=>
  string(15) "int(9) unsigned"
  [1]=>
  string(7) "int(15)"
  [2]=>
  string(11) "varchar(30)"
  [3]=>
  string(4) "text"
}


Ik zal om 't "give a man a fish"-gehalte wat hoger te maken de uitleg plaatsen:

Wat je wil is <matchX>|<matchY>|<matchZ>; de | is een "OR" (alternation).

Goed, dan elk dingetje apart nemen; we beginnen met int(9) unsigned:
  • We willen matchen: int( waarbij je de ( moet escapen: dat wordt dus int\(.
  • Vervolgens 1 of meer cijfers (+ operator a.k.a. "one or more" -> repetition) en dus schrijven we: [0-9]+.
  • Vervolgens weer een ) die escaped moet worden: \).
  • Dan, optioneel, een whitespace: \s -> character class
    (eventueel zou daar een + achter mogen wil je meer dan 1 whitespace (meerdere tabs/spaties/etc.) matchen)
  • Dan nog de literal "unsigned"; dus we schrijven unsigned
  • ^ Maar die vorige twee punten zijn optioneel (zero or one) dus groupen we die met ( en ) en zetten we daar de ? operator achter
Voila, matchX is klaar. Voor matchY idem; zonder de laatste drie puntjes van matchX uiteraard. En voor matchZ enkel de literal "text". C'est tout. De hele regex maken we case-insensitive met de i pattern modifier en je hebt je regex.

De "requirements" die je hier in dit topic geeft zijn vrees ik wat kort door de bocht (zie ook Jaap-Jan hier beneden) en mijn "oplossing" komt maar deels in de buurt van wat je wil bereiken en dus ga je nu met deze vers opgedane nieuwe kennis mooi zelf puzzelen hoe je jouw beoogde resultaat krijgt natuurlijk ;) :>

[ Voor 130% gewijzigd door RobIII op 31-01-2012 23:45 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • Jaap-Jan
  • Registratie: Februari 2001
  • Laatst online: 02:48
Als je van named capturing houdt:
code:
1
'/(?P<datatype>[a-z]+)(\((?P<size>[0-9]+)\))?( (?P<type>[a-z]+))?/


Maar als je doel is om een data type volledig te parsen, hoed je dan voor zulke dingen:
BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE
Ook voor DECIMAL data- types is dit niet geschikt. :)
Ik zal om 't "give a man a fish"-gehalte wat hoger te maken de uitleg plaatsen:
Regexes zijn sowieso onleesbaar. Na het schrijven afblijven, zou ik zeggen. Als het leesbaar moet zijn, dan probeer je niet alles op één regel te proppen. :X

[ Voor 66% gewijzigd door Jaap-Jan op 31-01-2012 23:23 ]

| Last.fm | "Mr Bent liked counting. You could trust numbers, except perhaps for pi, but he was working on that in his spare time and it was bound to give in sooner or later." -Terry Pratchett


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 04-07 15:03

NMe

Quia Ego Sic Dico.

Dit zijn geen dingen waar je een regexp voor wil gebruiken. Een parser (al dan niet stack based afhankelijk van je requirements) is veel en veel robuuster. Vertel eens waarom je dit nodig hebt. Wat is je in- en output?

'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!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
RobIII schreef op dinsdag 31 januari 2012 @ 23:12:
Ik hou er niet van zaken voorgekauwd en wel aan te leveren maar bekijk dit eens:
code:
1
int\([0-9]+\)\s(unsigned)?|varchar\([0-9]+\)|text
Dit doet idd precies wat ik wil, totdat ik de Post van Jaap-Jan las, maar daar kom ik zo op terug. In ieder geval bedankt voor de uitleg dat maakt het iets makkelijker. Ik wil mysql datatypes gaan uitlezen die ik door middel van een query terug krijg. In één cell staat dus deze informatie, wat Jaap-Jan al eerder aangaf in zijn link naar de numeric-type overview.
Jaap-Jan schreef op dinsdag 31 januari 2012 @ 23:16:
Als je van named capturing houdt:
code:
1
'/(?P<datatype>[a-z]+)(\((?P<size>[0-9]+)\))?( (?P<type>[a-z]+))?/


Maar als je doel is om een data type volledig te parsen, hoed je dan voor zulke dingen:

[...]


Ook voor DECIMAL data- types is dit niet geschikt. :)
Dat named-capturing is wel lijp, daar ga ik zeker naar kijken, want ik was nooit echt een liefhebber van resulten uit een lijst ophalen d.m.v. een index nummer.

Maar decimal types had ik zo nog niet aan gedacht en dit zelfde geldt voor zerofill, volgens dus dat wordt punt twee. Maar met de uitleg die Roblll mij heeft gegeven moet ik deze zelf wel kunnen realiseren. Ik zal er vanmiddag eens mee gaan prutsen om te kijken of ik er iets uit kan krijgen.
NMe schreef op woensdag 01 februari 2012 @ 00:17:
Dit zijn geen dingen waar je een regexp voor wil gebruiken. Een parser (al dan niet stack based afhankelijk van je requirements) is veel en veel robuuster. Vertel eens waarom je dit nodig hebt. Wat is je in- en output?
Is een parser geen overkill hiervoor? Misschien omdat uit de eerste beschrijving niet helder was dat het steeds gaat om één regel i.p.v. ze uit een tekst op te halen. Of bedoel je iets in de trend van met strpos eerst naar bepaalde indicatoren kijken e.g. unsigned en dan een regex patroon er bij schrijven die hem in één keer goed ophaalt?

Acties:
  • 0 Henk 'm!

  • wackmaniac
  • Registratie: Februari 2004
  • Laatst online: 09-07 10:11
Nou weet ik niet wat voor query je krijgt, maar als je een DESCRIBE-query doet krijg je de types en evt. andere eigenschappen redelijk op een bordje aangeleverd van onze vrienden van MySQL.

Read the code, write the code, be the code!


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
wackmaniac schreef op woensdag 01 februari 2012 @ 09:08:
Nou weet ik niet wat voor query je krijgt, maar als je een DESCRIBE-query doet krijg je de types en evt. andere eigenschappen redelijk op een bordje aangeleverd van onze vrienden van MySQL.
Die gebruik ik ook inderdaad, maar de datatype met zijn attributen worden aangeleverd als een string en aangezien er aardig wat informatie inzit wil ik deze uit elkaar halen, zodat ik ieder ding apart kan behandelen. Bijvoorbeeld wanneer de string unsigned bevat dan zal er een vinkje aan moeten staan.

Acties:
  • 0 Henk 'm!

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 10-07 13:00

Janoz

Moderator Devschuur®

!litemod

4Real schreef op woensdag 01 februari 2012 @ 08:23:
Is een parser geen overkill hiervoor? Misschien omdat uit de eerste beschrijving niet helder was dat het steeds gaat om één regel i.p.v. ze uit een tekst op te halen. Of bedoel je iets in de trend van met strpos eerst naar bepaalde indicatoren kijken e.g. unsigned en dan een regex patroon er bij schrijven die hem in één keer goed ophaalt?
Absoluut geen overkill. Regexpen zou je eigenlijk pas moeten gebruiken als er geen andere mogelijkheid is. Ze zijn lastig, buggy, onleesbaar en daaruitvolgend slecht onderhoudbaar.

Ik weet niet of ik het probleem goed begrepen heb, maar wanneer het daadwerkelijk die 3 strings moet herkennen is een combinatie van 3 if's (of een case) natuurlijk oneindig veel simpeler.

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!

  • Spider.007
  • Registratie: December 2000
  • Niet online

Spider.007

* Tetragrammaton

Janoz schreef op woensdag 01 februari 2012 @ 09:29:
[...]

Absoluut geen overkill. Regexpen zou je eigenlijk pas moeten gebruiken als er geen andere mogelijkheid is. Ze zijn lastig, buggy, onleesbaar en daaruitvolgend slecht onderhoudbaar.

Ik weet niet of ik het probleem goed begrepen heb, maar wanneer het daadwerkelijk die 3 strings moet herkennen is een combinatie van 3 if's (of een case) natuurlijk oneindig veel simpeler.
Als je ze lastig vindt zijn ze onleesbaar, buggy en slecht onderhoudbaar. Als je ze niet lastig vindt; gaan de andere nadelen niet op. Zo zijn de tot nu toe geposte oplossingen in mijn ogen geen van allen lastig en gaan daarmee de rest van de nadelen ook niet op.

Aangezien het om de uitvoer van een mysql DESCRIBE query gaat zijn natuurlijk niet alleen de 3 voorbeelden iets wat moet matchen.



De topicstarter kan evt. ook naar information_schema.COLUMNS kunnen kijken deze is al in een iets leesbaarder formaat

---
Prozium - The great nepenthe. Opiate of our masses. Glue of our great society. Salve and salvation, it has delivered us from pathos, from sorrow, the deepest chasms of melancholy and hate


Acties:
  • 0 Henk 'm!

  • 4Real
  • Registratie: Juni 2001
  • Laatst online: 14-09-2024
Janoz schreef op woensdag 01 februari 2012 @ 09:29:
[...]

Absoluut geen overkill. Regexpen zou je eigenlijk pas moeten gebruiken als er geen andere mogelijkheid is. Ze zijn lastig, buggy, onleesbaar en daaruitvolgend slecht onderhoudbaar.

Ik weet niet of ik het probleem goed begrepen heb, maar wanneer het daadwerkelijk die 3 strings moet herkennen is een combinatie van 3 if's (of een case) natuurlijk oneindig veel simpeler.
Regex vond ik wel een mooie oplossing, ondanks het tig keer complexer is en volgens mij ook nog eens langzamer is. Volgens mij loop ik ook verder tegen problemen aan, want bij een ENUM of SET moet ik alles tussen de haakjes ook allemaal weer uit halen.

Spider.007 heeft hier een goed punt
Spider.007 schreef op woensdag 01 februari 2012 @ 09:37:
[...]
Als je ze lastig vindt zijn ze onleesbaar, buggy en slecht onderhoudbaar. Als je ze niet lastig vindt; gaan de andere nadelen niet op. Zo zijn de tot nu toe geposte oplossingen in mijn ogen geen van allen lastig en gaan daarmee de rest van de nadelen ook niet op.

Aangezien het om de uitvoer van een mysql DESCRIBE query gaat zijn natuurlijk niet alleen de 3 voorbeelden iets wat moet matchen.



De topicstarter kan evt. ook naar information_schema.COLUMNS kunnen kijken deze is al in een iets leesbaarder formaat
De information_schema.COLUMNS levert idd deze informatie beter aan, echter moet ik voor de unsigned,zerofill nog steeds een string uit elkaar halen, maar ik krijg datatype wel direct terug en die kan ik dan wel een een switch statement gooien, zodat waar nodig ik extra handelingen kan uit voeren om alle informatie er uit te halen op de manier dat ik dat wil.

Acties:
  • 0 Henk 'm!

  • wackmaniac
  • Registratie: Februari 2004
  • Laatst online: 09-07 10:11
De vraag is wat je met de informatie wilt doen, maar als je de lijst van ondersteunde datatypes van MySQL bekijkt is een regex voor een of twee datatypes redelijk eenvoudig en oneindig veel leesbaarder (je zou de tinyint, smallint, mediumint, bigint en integer best samen kunnen schuiven). Let er alleen wel op dat er wel een beste hoeveelheid aan datatypes is (http://dev.mysql.com/doc/...n/data-type-overview.html).

Read the code, write the code, be the code!


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 04-07 15:03

NMe

Quia Ego Sic Dico.

Het gaat er niet om of een regexp makkelijk of mogelijk is, het gaat erom of ze al dan niet geschikt zijn om op waterdichte wijze je string goed te kunnen parsen. Er zijn betere methodes en toch vasthouden aan een reguliere expressie lijkt me niet handig.

'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.

Pagina: 1