# regular expression met een dakje.

## robertdb

Hallo allen,

Ik heb flink gezocht met google, maar kon niet vinden wat ik zocht. De meest geschikte plaats om dit te vragen leek mij dit forum.

Ik probeer een regex te maken die een logfile filtert, om concreet te zijn een voorbeeldje:

```

$ cat iets.txt

123 hallo

234 hallo

```

Deze omschrijving is wat ik zoek:

karakters gevolgd door "-spatie-hallo", maar niet de cijfers "123" (letterlijk, achter elkaar een twee drie.)

Dus de eerste regel zou niet getoond moeten worden, de tweede wel.

nu dacht ik aan bracket/blokhaak ([) en caret/dakje (^) als oplossing.

```

$ cat iets.txt | grep -E "[^123] hallo"

234 hallo

```

Dat werkt dus, echter niet zoals ik bedoel, omdat dit ook werk: (hier is 123 aangepast naar 132...)

```

$ cat iets.txt | grep -E "[^132] hallo"

234 hallo

```

Na lezen blijkt dat [^...] resultaten weglaat waar een (elk) karakter uit die klasse of range (-) overeenkomt. Ik zoek eigenlijk -letterlijk- 123, achterelkaar, drie cijfers; een twee drie.

heb al zitten testen met de volgende commando's:

```

$ cat iets.txt | grep -E "[^123] hallo"

$ cat iets.txt | grep -E "[^[123]] hallo"

$ cat iets.txt | grep -E "[^(123)] hallo"

$ cat iets.txt | grep -E "[^[1][2][3]] hallo"

$ cat iets.txt | grep -E "[^(1)(2)(3)] hallo"

```

Weet iemand hoe ik dat zou moeten oplossen? Het moet een (1) regular expression zijn, niet een reeks van command's.

----------

## koder

 *robertdb wrote:*   

> karakters gevolgd door "-spatie-hallo", maar niet de cijfers "123" (letterlijk, achter elkaar een twee drie.)

 

Wel dat is gewoon:

```
^[^1][^2][^3]\s+hallo
```

Het eerste 'dakje' wil hier zeggen "aan het begin van de regel". Als je dat niet nodig hebt, haal je het gewoon weg.

Verder staat er dat het eerste teken niet '1' mag zijn, het tweede niet '2' en het derde niet '3'. Na die drie eerste tekens komt er minstens één spatie, gevolgd door het woord "hallo". Daarna mag desnoods nog iets komen, maar daar wordt geen rekening mee gehouden.

Als het exact één spatie is, dan moet je de '+' weghalen.

Nu, wel ik kan het hier wel niet testen omdat ik op deze NT bak niks heb dat regex gebruikt en niks mag installeren. Ff testen dus!  :Rolling Eyes: 

greetz

koder

----------

## garo

Dat zal niet werken, "234 hallo" zal niet worden goedgekeurd omdat je eigenlijk zegt dat de regel moet beginnen met " hallo".

En als je de "^" helemaal vooraan zou weghalen zou je wel "123 hallo" toelaten, omdat je dan 123 voor de regexp toelaat en de regexp alleen " hallo" laat checken.

----------

## koder

Maar als je dan toch grep gaat gebruiken, dan kan je net even goed vragen om te geven waar de match niet voorkomt. Ik denk dat dat de -v optie is, en dan kan je dus gewoonweg doen:

```
grep -v "^123 "
```

Maar nogmaals, kan niks testen.

greetz

koder

----------

## garo

Als ik er mag vanuit gaan dat er niks achter " hallo" komt, er voor " hallo" alleen cijfers van "000" tot "999" komen en er voor deze cijfers niks komt, dan zou ik het zo doen:

```
grep -P "^([02-9][013-9][0124-9]|1\d[0124-9]|1[013-9]\d|\d2[0124-9]|[02-9]2\d|\d[013-9]3|[02-9]\d3) hallo$"
```

(De -P optie is omdat ik de grep regexps niet goed ken, maar die van perl wel)

Als het met meerdere regexps mag, dan zou ik het zo doen:

```
grep " hallo" | grep -v "^123"
```

----------

## robertdb

 *koder wrote:*   

> 
> 
> Wel dat is gewoon:
> 
> ```
> ...

 

Wow, zo simpel, dat is exact wat ik bedoel. Soms is de oplossing makkelijker dan gedacht.

Groet,

Robert de Bock.

----------

## garo

 *robertdb wrote:*   

>  *koder wrote:*   
> 
> Wel dat is gewoon:
> 
> ```
> ...

 

Zoals ik al zei, dit werkt niet, "234 hallo" wordt alleen aanvaard met "-P" en "132 hallo" wordt nooit aanvaard, terwijl dit eigenlijk wel moet.

----------

## robertdb

 *garo wrote:*   

>  *robertdb wrote:*    *koder wrote:*   
> 
> Wel dat is gewoon:
> 
> ```
> ...

 

Nou, het is een nogal ingewikkelde vraag, wellicht heb ik hem niet goed gesteld, maar het antwoord van koder was wel correct. Even ter bevestiging:

deze patronen moeten getoond worden:

132 hallo

234 hallo

deze patronen moeten niet getoond worden:

123 hallo

Dus dan is koders truc correct: (iets aangepast)

"[^1][^2][^3] hallo"

```

$ cat iets.txt                                      

123 hallo

234 hallo

132 hallo

$ cat iets.txt | grep -E "[^1][^2][^3] hallo"       

234 hallo

$

```

F*ck, je hebt helemaal gelijk. Dat is opvallend. Hoe is het dan te verklaren dat 132 wel matcht, dus niet ge-output wordt? in woorden:

"[^1][^2][^3] hallo"

niet 1, gevolgd door niet 2, gevolgd door niet 3 spatie "hallo"

Nou, uitleg is heel hartelijk welkom uiteraard.

----------

## koder

Ik vrees dat Garo gelijk heeft.   :Sad: 

Ik had niet lang genoeg nagedacht toen ik postte, maar het klopt inderdaad dat mijn oplossing geen rekening houdt met de volgorde.

Hier is een hele lange. Hou u vast!

```
^(12[^3]|1[^2]3|[^1]23|[^123]{3}|[123][0-1,3-9][0-2,4-9]|[0,2-9][123][0-2,4-9]|[0,2-9][0-1,3-9][123])\shallo
```

Het zou wel eens wat overbodige zaken kunnen bevatten, maar ik ben 99% zeker dat deze wel altijd werkt!

(maar nogmaals, kan hier helaas niet testen)

greetz

koder

----------

## robertdb

 *koder wrote:*   

> 
> 
> Hier is een hele lange. Hou u vast!
> 
> ```
> ...

 

slik, die is inderdaad wel lang... en dan te bedenken dat het voorbeeldje slecht 123 is, en mijn situatie een ip-adres...

Maar, toch snap ik het nog niet helemaal, waarom is "[^1][^2][^3] hallo" niet goed, de volgorde lijkt onbelangrijk in dat voorbeeld. Is er alsnog iemand die dat kan uitleggen?

want dit is wel zoals ik verwacht had:

```

$ cat iets.txt                                      

123 hallo

234 hallo

132 hallo

$ grep -E "[1][2][3] hallo" iets.txt                

123 hallo

$

```

Alvast bedankt.

----------

## BlackEdder

[^1][^2][^3] hallo werkt niet omdat 132 hallo er al door [^1] uitgefilterd wordt. 

Je zegt er maar geen 1 staan ([^1]) en dat staat er wel bij 132.

----------

## frenkel

Of gebruik gawk...

$ gawk '{print $2 }' hallo.txt

Dit geeft de 2e colom weer. In dit geval is dat na de cijfers + spatie, dus het woord hallo.

Frank

----------

## robertdb

 *Frenkel wrote:*   

> Of gebruik gawk...
> 
> $ gawk '{print $2 }' hallo.txt
> 
> Dit geeft de 2e colom weer. In dit geval is dat na de cijfers + spatie, dus het woord hallo.
> ...

 

Jep, ik snap de intensie, net als "grep -v ..." maar het moet een regex zijn, omdat het in een ander programma gebruikt gaat worden, dus ik heb geen keuze in programma's ofzo.

Bedankt voor je hulp.

----------

## koder

Wel, mijn regular expression hierboven (die hele lange) is juist hoor. Heb je die al geprobeerd?

(De awk-oplossing van Frenkel houdt helaas geen rekening de voorwaarde dat een regel niet met 123 mag beginnen.)

greetz

koder

----------

## Lion

Het was even puzzelen, maar hier heb je een kortere:

egrep '^([^1]|.[^2]|..[^3]).* hallo' file

Ofwel: 

- Aan het begin van de regel (^)

- niet een 1 op de eerste plaats of niet een twee op de tweede plaats of niet een 3 op de derde plaats (ofwel alles wat niet '123' is)

- gevolgd door een willekeurige hoeveelheid troep, gevolgd door ' hallo'

Hiermee test je nog niet of de regel inderdaad met een getal begint, alleen of-ie niet met '123' begint en wel 'hallo' bevat. Dat voldoet precies aan jouw oorspronkelijke omschrijving 'karakters gevolgd door "-spatie-hallo", maar niet de cijfers "123" (letterlijk, achter elkaar een twee drie.)'

Als die 'karakters' per se een ip-nummer moeten zijn, en de ' hallo' daar direct op aan moet sluiten, wordt het iets lastiger, temeer daar het aantal karakters in een ip-adres kan varieren.

Regexps kennen helaas geen NOT (a AND b AND c), dus zet je dat om naar (NOT a) or (NOT b) or (NOT c). Simpele Boolese logica...

Precies drie karakters, die echter niet '123' mogen zijn, direct gevolgd door ' hallo' kan ook:

egrep '^([^1]..|.[^2].|..[^3]) hallo' file

Voldoet dit aan je eisen? Zo nee, dan denk ik graag nog even verder.

----------

## robertdb

 *Lion wrote:*   

> Het was even puzzelen, maar hier heb je een kortere:
> 
> egrep '^([^1]|.[^2]|..[^3]).* hallo' file
> 
> 

 

Ik denk dat je hem hebt gevonden, best wel slim zo en redelijk kort. Cool, erg bedankt man!

----------

## koder

 *Lion wrote:*   

> Regexps kennen helaas geen NOT (a AND b AND c), dus zet je dat om naar (NOT a) or (NOT b) or (NOT c). Simpele Boolese logica...

 

Dat brengt vage herinneringen terug tot leven... "De Wetten van De Morgan", right?

Hhhhuuuhhhh... ik krijg rillingen...    :Wink: 

greetz

koder

----------

## Lion

 *koder wrote:*   

> Dat brengt vage herinneringen terug tot leven... "De Wetten van De Morgan", right?
> 
> Hhhhuuuhhhh... ik krijg rillingen...   
> 
> 

 

Yep, dat was hem! Errug nuttig als je daar een beetje creatief mee om weet te gaan!

----------

