Regexp awk-ban

Egy másik topikban szó volt arról, bizonyos napokat színezni kellene a cal parancs kimenetében. Erre gyorsan összetákoltam egy nem igazán általános, de jó megoldást, viszont a saját scriptemet sem értem egészen, pontosabban az egyik regexpet.A cal kimenete nálam így néz ki:

     August 2013    
Su Mo Tu We Th Fr Sa
             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

A fejléc figyelmen kívül hagyásához írtam egy ilyen regexpet:

/^ *[^[:digit:] ]/

Viszont eredetileg így akartam, csak ez nem működött jól:

/^ *[^[:digit:]]/

Az elképzelés az, hogy sor elejét követően vagy létező, vagy nem létező szóközök után amennyiben nem szám karakter jön, akkor illeszkedik a regexpre a minta, s kihagyom a színezést. Az akció része most nem érdekes.

Úgy látom, a második változatom illeszkedik arra az esetre, amikor szóközöket követően szám karakter jön. Ez egy nyakatekert értelmezésben persze lehet:

illeszkedik a sor elejére, illeszkedik valahány, de nem az összes szóközre - például nulla darabra -, majd a szóközre, amely valóban nem szám karakter.

Az a kérdésem, hogy a / */ a leghosszabb, vagy a legrövidebb olyan szakaszra illeszkedik, amelyre tud illeszkedni?

GNU Awk 4.0.2

amiről szó van.

Hozzászólások

"illeszkedik a sor elejére, illeszkedik valahány, de nem az összes szóközre - például nulla darabra -, majd a szóközre, amely valóban nem szám karakter."

Úgy látszik, tényleg ez történik:


cal | perl -lne 'if (/^ *[^[:digit:]]/p) {print "[${^MATCH}][${^POSTMATCH}]"}'

(Igen, tudom, perl, de kérdés szempontjából a regex ugyanúgy viselkedik, mint awkban.)

Alapvetően egyébként a * módosító "kapzsi", azaz a lehető leghosszabb szakaszra illeszkedik.

A POSTMATCH változó mit ad vissza? Vagy azért raktad bele, hogy áttekinthetőbb legyen a kimenet? Gondolom, a MATCH a lényeg.

Alapvetően egyébként a * módosító "kapzsi", azaz a lehető leghosszabb szakaszra illeszkedik.

Jó, de akkor itt miért nem? Kiszúrt magának, pikkel rám? :)

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

A ${^POSTMATCH} a stringnek az illeszkedő rész-string utáni részét tartalmazza, csak azért tettem bele, hogy világos legyen, melyik sorról van szó. perldoc perlvar BTW.

"Jó, de akkor itt miért nem? Kiszúrt magának, pikkel rám? :)"

Nem, éppen ellenkezőleg: szeretne mindenáron a kedvedre tenni :)

Vegyük a " 4 5 6 7 8 9 10" sort.
A " *" a lehető legtöbb szóközre szeretne illeszkedni, tehát először megnézi egyre. Utána viszont számjegy áll, tehát ezt az esetet eldobja.
Utána megnézi nulla darab szóközre (a * definíciója ezt megengedi), a következő karakter szóköz (azaz nem számjegy, ahogy írtad), tehát az egész minta illeszkedik, öröm, boldogság.

szerk:

cal | perl -mre=debug -lne 'if (/^ *[^[:digit:]]/p) {print "[${^MATCH}][${^POSTMATCH}]"}'

Így meg is magyarázza, hogy mit csinál.

Aha, tehát másként működik, mint amit erről _gondoltam_. Valamiért azt képzeltem, hogy ha eljut valameddig, akkor oda leszúrja a pointert, s onnan nézi tovább. Ha onnan illeszkedik, akkor jó, ha nem, akkor pedig nem.

Ehelyett ez végig sakkozza az összes lehetséges megoldást, és ha van illeszkedés, akkor örül. Ha pedig sehogy sem tudja a regexpet a mintára paszírozni, akkor nincs illeszkedés.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Tudtommal a perl volt az egyetlen, amelyiknel lehetett legrovidebb illeszkedest eloirni, altalaban a regexpek a leghosszabbra illeszkednek.

Nem nagyon értem a kérdést. Amit én tudok regexppel kapcsolatos szabályok (és amiket szerintem neked nem kell magyaráznom, mert tudod)

- összetett regexp esetén minden résznek illeszkednie KELL - azaz "ab" minta esetén lennie kell a-nak is, b-nek is a vizsgált szövegben a találathoz (és persze közvetlenül egymás után kell álljanak)

- az első (valódi, azaz 0-nél hosszabb) találat számít, még akkor is, ha a vizsgált szövegrészen belül később lenne hosszabbb illeszkedés is. "ablak az abba lemezeire", ha a minta "ab*", akkor a kezdő pozícióban van egy 1 hosszú találat (a) meg egy 2 hosszú (ab), és hiába van hátrébb egy 3 hosszú (abb) is, az elején levő ab-re fog illeszkedni. (Viszont ha a minta alapján lehet 0 hosszú a találat, és nincs "valódi" találat, akkor a sor eleji "semmi"-re fog 0 hosszan ileszkedni - azaz lesz találat, de 0 hosszúságban - ami persze nem ugyanaz, mint a "nincs találat")

- ha ugyanabban az "első" kezdőpozícióban van többféle hosszúságú találat, a hosszabb lesz a találat. Előző példánál ezért volt az "ab" a találat az "a" helyett.

Ellenben nincs meghatározva, hogy ha a regexpől több *-os illeszkedne, akkor azok hogyan fognak illeszkedni:
szöveg: aaaaaaa
regexp: a*a* - nincs meghatározva, hogy melyik a* mennyi a-ra fog illeszkedni. (Sejtésem szerint a regexp libek többsége esetén az első a* illeszkedik 7 db a-ra, a második a* pedig 0 db-ra - de ez sejtés, és tudtommal nincs szabályozva - sőt többségében dokumentálva sem, hogy az adott verzió mit cisnál.)

Köszönöm.

Ott tévedtem el - amit fentebb írtam -, hogy vélelmeztem, a /^ */ részben a legtöbb szóközig eljut, utána nézi azt, hogy nem szám, s mivel nekem szám jön, vélelmeztem, nem ad illeszkedést. Arra nem gondoltam, hogy a részkifejezés illeszkedése után szükség esetén visszafelé is mozgatja a pointert, ha az egész kifejezésre nézve így találhat illeszkedést. Itt ez történt. Az utolsó szóközt nem számjegyre illeszkedő karakternek nézve - /[^[:digit:]]/ -, s a /^ */ részt a lehetségesnél eggyel rövidebb részre illesztve az egész kifejezés már illeszkedni fog.

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE