Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[Regexp] Hulp bij herhalingen van matches

Pagina: 1
Acties:

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
Ik ben bezig met een beetje proeven aan regular expressions.
Hiervoor heb ik een door quake 3 gegenereerde logfile gepakt.
Hieruit wil ik het volgende matchen:
code:
1
2
3
4
5
6
7
8
387.2 Weapon_Stats: 0 Gauntlet:0:3:0:0 MachineGun:354:105:0:0 Shotgun:242:77:7:1 R.Launcher:69:35:9:5 LightningGun:0:0:4:0 Railgun:24:9:2:0 Plasmagun:0:0:5:0 Given:4754 Recvd:2246 Armor:615 Health:325
387.2 Weapon_Stats: 1 MachineGun:737:228:0:0 Shotgun:583:168:17:10 R.Launcher:10:6:2:0 LightningGun:257:81:6:2 Railgun:5:1:2:0 Plasmagun:8:2:1:1 Given:4419 Recvd:3195 Armor:120 Health:325
387.2 Weapon_Stats: 2 MachineGun:637:161:0:0 Shotgun:418:69:9:6 R.Launcher:5:4:1:1 LightningGun:457:148:9:3 Plasmagun:60:17:2:0 Given:3581 Recvd:3211 Armor:350 Health:300
387.2 Weapon_Stats: 3 Gauntlet:0:1:0:0 MachineGun:607:177:0:0 Shotgun:44:13:3:2 R.Launcher:9:5:1:1 LightningGun:422:103:7:6 Given:2533 Recvd:3311 Armor:470 Health:150
387.2 Weapon_Stats: 4 MachineGun:635:219:0:0 Shotgun:198:44:8:6 R.Launcher:2:1:2:1 LightningGun:126:37:3:3 Plasmagun:13:2:2:1 Given:2380 Recvd:4062 Armor:200 Health:175
387.2 Weapon_Stats: 5 MachineGun:1008:263:0:0 Shotgun:143:38:6:3 LightningGun:303:89:5:4 Railgun:5:2:1:0 Plasmagun:0:0:1:1 Given:3133 Recvd:3562 Armor:60 Health:25
387.2 Weapon_Stats: 6 MachineGun:426:113:0:0 Shotgun:473:140:15:8 R.Launcher:6:2:4:2 LightningGun:92:36:5:3 Plasmagun:31:6:1:0 Given:2754 Recvd:3076 Armor:110 Health:75
387.2 Weapon_Stats: 7 MachineGun:773:204:0:0 Shotgun:275:56:9:5 R.Launcher:8:1:2:1 LightningGun:372:139:8:5 Plasmagun:27:4:2:1 Given:3270 Recvd:4161 Armor:45 Health:225

Dit is me gelukt met de volgende expressie:
code:
1
[0-9]*\.[0-9]*\sWeapon_Stats:\s[0-9]\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\sGiven:([0-9]*)\sRecvd:([0-9]*)\sArmor:([0-9]*)\sHealth:([0-9]*)

Hier heb ik enkele vragen over waar ik wel wat hulp bij kan gebruiken.
Allereerst zal ik mijn regexp een beetje ontleden ter verduidelijking.
code:
1
2
3
4
5
6
7
8
9
10
[0-9]*\.[0-9]*\sWeapon_Stats:\s[0-9]\s
match:
387.2 Weapon_Stats: 0 
387.2 Weapon_Stats: 1 
387.2 Weapon_Stats: 2 
387.2 Weapon_Stats: 3 
387.2 Weapon_Stats: 4 
387.2 Weapon_Stats: 5 
387.2 Weapon_Stats: 6 
387.2 Weapon_Stats: 7

Het stukje erachteraan match de statistieken van de wapens:
code:
1
2
3
([^:]*:[^:]*:[^:]*:[^:]*:[0-9]*)\s
match:
MachineGun:637:161:0:0

Dit stukje word enkele keren herhaald om bijvoorbeeld ook de gegevens van de shotgun etc te matchen.
Hierbij loop ik echter tegen een probleem aan:
Niet iedereen gebruikt ale wapens. Wapens die niet gebruikt zijn komen niet in de statistieken voor. Hierdoor is niet elke regel even lang?

Als laatste het stukje om de damage ontvangen en uitgedeeld te matchen
code:
1
2
3
4
5
Given:([0-9]*)\sRecvd:([0-9]*)\sArmor:([0-9]*)\sHealth:([0-9]*)
match:
Given:2754 Recvd:3076 Armor:110 Health:75
Given:3270 Recvd:4161 Armor:45 Health:225
etc...


Ik vind de regexp zelf gruwelijk lelijk en onleesbaar. Is er een manier om het stukje om de statistieken van de wapens te matchen 1 keer op te schrijven en dan te herhalen? Bijvoorbeeld met {1,6} oid?
Wie heeft er nog andere tips voor me?
Zou trouwens goed kunnen zijn dat er nu wat mensen van hun stoel flikkeren van het lachen. :P Maar het zijn mijn eerste stappen in de regexp wereld dus vergeef me. :P
Wist geen betere titel voor dit topic

Verwijderd

Ik zou eerst de boel opknippen.

Dus eerst:
\d+\.\d+\s+Weapon_Stats:\s+\d+((?:\s+[A-Za-z.]+(?::\d+){4})*)(?:(\s+\w+:\d+)*)

\d = digit = [0-9]
\s = whitespace
\w = word character = [A-Za-z0-9_]
( ) = capturing group
(?: ) = non-capturing group
+ = 1 of meer van het voorgaande
* = 0 of meer van het voorgaande
{4} = exact 4 keer het voorgaande

Vervolgens kun je per regel heel makkelijk de "wapens" en de "andere stats" eruit halen met iets eenvoudigere deel-regular-expressions.

  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
Ah kijk. die non capturing groups alleen al maken mijn regexp al vele malen eenvoudiger.
Bedankt voor dit voorbeeld en de aanpak.
Heeft me weer een hoop geholpen met hoe ik zoiets in de toekomst aan zou pakken.

  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Is het niet veel handiger om gewoon te splitten op spaties en : ?

Reguliere expressies zijn echt niet altijd de beste oplossing hoor ;)

Blog [Stackoverflow] [LinkedIn]


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Inderdaad splitsen op whitespace (spaties, tabs), dan vervolgens de 'sectieNaam' opvragen (dus de tekenreeks tot en met de eerste dubbele punt). Via een switch kun je op basis daarvan de juiste 'parser' aanroepen.

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//section is volledig het volledige blok tussen de spaties
//sectionName  naam tot eerste :

switch(sectionName.ToLower())
{
  case "gauntlet":
  case "machinegun": 
  case ....
    ParseWeaponStats(section);
    break;
  case "given":
  case "recvd":
  case ...
    ParseHealthStats(section);
}

If it isn't broken, fix it until it is..


  • Gehakt
  • Registratie: Juli 2002
  • Laatst online: 24-10 20:19
De voorbeeld tekst uit de logfile is echter niet het doel.
Het doel is het beter leren gebruiken/begrijpen van Regular Expressions.
De tekst is hierbij een middel.

Dus in principe doet de vraag of reguliere expressies hier de beste oplossing voor zijn er niet heel erg toe.
Toch nog bedankt voor de extra toevoegingen. :)
Wat me nog wel bij een klein ander vraagstuk brengt:
Zijn er duidelijke voorwaarden waaraan men kan toetsen of reguliere expressies het juiste middel zijn om een probleem op te lossen?
Of is dit voornamelijk op gevoel afgaan?

[ Voor 25% gewijzigd door Gehakt op 08-05-2008 10:48 ]


  • Wolfboy
  • Registratie: Januari 2001
  • Niet online

Wolfboy

ubi dubium ibi libertas

Op het moment dat je een duidelijk scheidingsteken tussen de velden hebt zal een reguliere expressie alleen maar complexer zijn. Als je een wat geavanceerdere detectie nodig hebt (of iets aan een bepaald patroon voldoet bijvoorbeeld) dan zou een reguliere expressie waarschijnlijk beter zijn.

Blog [Stackoverflow] [LinkedIn]


  • Niemand_Anders
  • Registratie: Juli 2006
  • Laatst online: 09-07-2024

Niemand_Anders

Dat was ik niet..

Zijn er duidelijke voorwaarden waaraan men kan toetsen of reguliere expressies het juiste middel zijn om een probleem op te lossen?
Of is dit voornamelijk op gevoel afgaan?
Reguliere (deel) expressies zijn verstandig als er een duidelijk patroon is en het 'pattern' voor jouw leesbaar. Als je dus van een website een reguliere expressie kopieert, probeer hem dan eerst zelf te ontleden hoe deze werkt. Mocht hij dan niet helemaal werken of later enigsinds aangepast worden, dan is dat minder lastig.

Zelf gebruik ik eigenlijk alleen reguliere expressies als ik stukjes tekst uit een grote tekst wil hebben (denk aan een references lijst onderaan een artikel welke alle linkjes toont). Op het moment dat meerdere soortgelijke regels (zoals een log bestand) moet parsen, dan val ik altijd terug naar het interpreter design pattern, ofwel de 'parser'.

Maar verander de 'opdracht' naar 'haal alle wapen statistieken op voor alle spelers'. Daarop kun je een zuivere regex maken. Even snel uit het hoofd:
([a-zA-Z0-9\.\-]+)(:([0-9]+)){4,4}

Ofwel een beschrijving met daarachter 4 getallen gescheiden door een dubbele punt.

If it isn't broken, fix it until it is..


Verwijderd

Gehakt schreef op woensdag 07 mei 2008 @ 21:14:
Ik vind de regexp zelf gruwelijk lelijk en onleesbaar.
Da's normaal bij regexen die ietsje meer moeten doen dan simpele checks/conversies/filters/etc.

/me schrijft liever 20 regels code dan een regex die achteraf alleen maar te begrijpen is door guru's. ;)
Pagina: 1