A következő érdekes dologgal találkoztam, és nem tudom megmagyarázni. Remélem, van köztetek olyan, aki jobban ért ehhez, mint én, és elmondja, mi miért.
Szóval van egy reguláris kifejezés: a+(ab)*(abc)*
Van egy minta: aaaababababcabcabc
A reguláris kifejezés, amennyire értem, úgy kéne működjön, hogy legalább 1, de lehetőleg minél több "a" betűt kéne találjon, aztán 0 vagy több "ab" kombinációt, aztán 0 vagy több "abc" kombinációt.
Pl. ezen az oldalon azt írják, hogy "the plus is greedy. That is, the plus causes the regex engine to repeat the preceding token as often as possible. Only if that causes the entire regex to fail, will the regex engine backtrack."
Ennek alapján az a+-nak 4 darab a-t kéne találnia, és ezután az ab 0-t talál, abc 0-t talál. A kifejezés illeszkedik, hiszen 0 ab és 0 abc az elegendő.
C#-ban ez állítólag így is működik, meg állítólag a Visual Studio search boxában is.
Viszont pl. ha linux alatt az egrep parancsot használom, akkor nem.
$ echo aaaababababcabcabc | egrep --color a+
az első 4 a betűt beszínezi,
echo aaaababababcabcabc | egrep --color a+(ab)*(abc)*
viszont beszínezi az egész mintát.
Szóval arra lennék kíváncsi, hogy ez miért van.
- 8395 megtekintés
Hozzászólások
Az egrep lesz ott slendrián a színezésével.
Itt kizárólag az 'a'-betűket színezi végig, ami ép elmével értelmezhető úgy, hogy számos helyen talált legalább egy a-t, amit az a-k mohó felzabálása után már nem követett semmi a kifejezés hátrelévő részéből.
- A hozzászóláshoz be kell jelentkezni
Az első verziód csak az első négy a-t színezi be?
Mert nálam az összeset.
A második példádban meg a teljes stringre illeszkedik a megadott regexp, miért gond, hogy beszínezi az egészet?
Én nem értek/látok valamit?
Mondjuk az furcsa, hogy pl. a python re modulban a második mintára egyetlen egyezést sem talál, de ez lehet, hogy valami pythonos galádság.
Aki tudja, csinálja, aki nem tudja, tanítja... Hm... igazgatónak talán még jó lennék. :)
- A hozzászóláshoz be kell jelentkezni
Az metakarakterek mohóságának kérdése, hogy az eredmény helyes vagy sem.
Ha +-nak mohónak kell lennie, akkor az egész kifejezés úgy illeszkedik, hogy a bevezető a-kon kívül semmi más.
Ennek mond ellent, ha a legteljesebb egyezés van kifestve.
Sajnos most messze enerváltabb vagyok annál, mint hogy végiggondolhatnám az RE-politikákat és következményeiket.
- A hozzászóláshoz be kell jelentkezni
Mostanra tökéletesen elvesztettem ama bizonyos fonalat.
Ahány környezetben kipróbáltam, annyiféle eredményt kaptam. :)
Úgyhogy ettől kezdve csak érdeklődőként vagyok jelen.
Mondjuk az angol idézethez talán a pythonos variációm passzol inkább.
Az általam tapasztalt shell-beli viselkedés és a pythontól elvárt, de nem teljesülő meg az én emlékeimhez illene.
Aki tudja, csinálja, aki nem tudja, tanítja... Hm... igazgatónak talán még jó lennék. :)
- A hozzászóláshoz be kell jelentkezni
Visszaléptetés (backtrack) miatt a mohó nem ész nélkül mohó. Szerintem. Különben a .* is továbbfutna, és nem ismerné fel pl. ezt:
echo 11dh22 | egrep --color .*dh.*
- A hozzászóláshoz be kell jelentkezni
(Lejjebb már jeleztem, h az egrep --color semmit nem mond, használj "sed -E"-t.) Amúgy egyetértünk, a mohóság nem mindenekfeletti egy regexp kiértékelésében.
- A hozzászóláshoz be kell jelentkezni
A színezés mond valamit, mert ha az egész minta nem illeszkedik, akkor nem színezne semmit. Én úgy értettem, hogy mivel az egész ki van színezve, ez bizonyítja, hogy a .* nem fal fel mindent, vagyis épp hogy megteszi, de a backtrack miatt mégis visszaáll a .* az "11" re, hogy utána a többi rész is tudjon illeszkedni. Jó fej.
- A hozzászóláshoz be kell jelentkezni
Kezdjük előlről. A te példád esetében igazad van, az egész sor színezése azt jelenti, hogy teljes illeszkedés van. Én másra próbáltam utalni. Ez volt az egyik első példa:
$ echo aaaababababcabcabc | egrep --color a+
aaaababababcabcabc
Ez jól láthatóan :-) minden a-t kiszínez, holott gyakorlatilag az összes hagyományos RE-t kezelni képes UNIX-eszköz a vizsgált tartományban pontosan az első találatig dolgozik, és a soron belül a későbbieket csak külön kérés hatására dolgozza fel. Lásd az általam többször is javasolt sed-et:
$ echo aaaababababcabcabc | sed -E 's/a+/X/'
Xbabababcabcabc
$ echo aaaababababcabcabc | sed -E 's/a+/X/g'
XbXbXbXbcXbcXbc
De tudtommal ugyanígy működik az ed-ben, a vi-ban, a perlben. Az awk match() fv-e az első előfordulást keresi, a sub() az elsőt cseréli (és csak később jelent meg a gsub() fv, ami ott is az összes előfordulást cseréli). Az expr parancs az első előfordulást keresi és adja vissza (vagy adja vissza a hosszát). Szóval az, hogy a grep valami érthetetlen oknál fogva mindegyik előfordulást színezi, az a kivétel. Ráadásul pont nem jól mutatja a tipikus regexp működést.
- A hozzászóláshoz be kell jelentkezni
grepnél, ha nincs mit színezni, nem is jelenik meg az outputon semmi (a -v,A,B itt nem volt opció, mielőtt vki belekötne)...
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
Az első példa egrep esetén kiszínezi az összes a betűt, mert a regexp-hez képest az összes egyezést megkeresi. Az alább az összes egyezést mutatja
echo aaaababababcabcabc | egrep -o --color "a+"
aaaa
a
a
a
a
a
A helyes találat csak aaaa lenne. A mohóság csak + jelre értendő.
A második pedig így meccsel:
a ->1*a 0*ab 0*abc
...
aaaa -> 4*a 0*ab 0*abc
aaaab -> 3*a 1*ab
...
aaaababababc -> 3*a 3*ab 1*abc
stb.
- A hozzászóláshoz be kell jelentkezni
Nem is inkább az összes, hanem a lehető leghosszabb egyezést keresi meg, ami illeszkedik a regexpre. "Tudományosan" úgy hívják ezt, hogy "maximal munch".
- A hozzászóláshoz be kell jelentkezni
Ne keverdjen a kettő!
A grep tényleg az összes lehetőséget keresi (hacsak meg nem mondod neki, hogy az első után békén is hagyhatja a keresés helyét).
Hogy az összes lehetőség egyes darabjait milyen megszállott bejárással keresi, és ebből a végén itt mi jön ki színesen, az a másik terület.
- A hozzászóláshoz be kell jelentkezni
Mármint abba tudja hagyni az első sor után, de olyan hol van benne, hogy az első "regexp-darab" után? Meg hát nincs is benne 2 féle regexp megvalósítás szerintem, úgyhogy nem hinném, hogy az illeszkedést úgy venné, hogy 4 "a" betű, aztán megvagyunk, színezésnél meg 3 "a" betű és a többiek...Ez a maximális hosszra illesztés amúgy a "normális", pl. a flex, sed, awk, stb. is így csinálja.
- A hozzászóláshoz be kell jelentkezni
Hát nem:
awk 'BEGIN { match("aaaababababcabcabc",/a+/); print RSTART,RLENGTH}'
1 4
Azaz: aaaa
- A hozzászóláshoz be kell jelentkezni
mert csak az a+-ra keresel.
pty@lucille:~/Asztal$ awk 'BEGIN { match("aaaababababcabcabc",/a+(ab)*(abc)*/); print RSTART,RLENGTH}'
1 18
Vagyis: de :)
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
Pedig jót szóltam, csak rosszkor és rosszul. :(
A példa arról szólt, hogy egyes esetekben elegendő a match() logikai értéke és érdektelen a "mi match" kérdésre adott válasz, ha az elsőre igen. A color opcióval szemben elég az első mintát megtalálni. Ha az egész sort kell valamiért vizsgálni, akkor folytatni kell az első minta után ugyanzzal, vagy másik mintával. Példa: Találjuk meg a házszámot: Május 1 utca 17-19/B 1. emelet 8.
- A hozzászóláshoz be kell jelentkezni
A válasz 17-19B, de a feladatod nem megoldható. Az adott példában ugyan igen, de mit szólsz ahhoz, hogy "1848 március 15-e tér"? Szóval szerintem nem lehet megmondani algoritmikusan, hogy egy utcanévben van-e szám és mennyi.
- A hozzászóláshoz be kell jelentkezni
:)
Aljas költői kérdés volt. Úgy 15 éve megodottam több mint 1M, össze-vissza elgépelt adaton, >99,99% biztonsággal a házszámig. A nagyon elírt ún. kiegészítő házszámok (itt /B...) esetén kicsit rosszabb az eredmény, de azokból úgy is kevés van.
- A hozzászóláshoz be kell jelentkezni
Lásd fölöttem...
- A hozzászóláshoz be kell jelentkezni
azt hogyan mondod meg neki, hogy az első után álljon le?
--
A legértékesebb idő a pillanat amelyben élsz.
http://phoenix_art.webmuvek.hu/
https://sites.google.com/site/jupiter2005ster/
- A hozzászóláshoz be kell jelentkezni
Szerintem sehogy. Legalábbis nem ismerek rá opciót, ha csak nem (|||)-kel tagolod a patternt, de az meg már nem ugyanaz a pattern.
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
-m 1 nem jó erre? Persze az a nagy kérdés, hogy mi volt a kérdés. Az, hogy az első megtalált sor után álljon le, vagy soron belül ha megvan az első találat, akkor már hátrébb ne keressen. (Ez utóbbi úgy rémlik nem fog menni.)
- A hozzászóláshoz be kell jelentkezni
Utóbbi - értelmezésem szerint.
a+(ab)*(abc)*
Esetén ha valamiben van 'a', akkor az illeszkedik. Erre írta vki, hogy 4db 'a'-t elég lenne kiszinezni, fölösleges a teljes illeszkedést vizsgálni. Szerintem meg, ha egy pattern akár teljesen is illeszkedhet, akkor azt kell jelölni, még akkor is, ha a pattern szigorú része már előzőleg teljesült. És a grep így is csinál.
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
Nekem személy szerint az a bajom, hogy:
echo aaaabababcabc | grep -E --color 'a+'
mindegyik különálló "a"-t kiszínezi, holott (az én) definícióm szerint amikor megtalálja az egymást követő 4 db. "a"-t, akkor a keresést akár be is fejezhetné - logikusan nekem az jönne ki belöle, hogy mivel az aaaa lesz a találat, azt színezze ki.
- A hozzászóláshoz be kell jelentkezni
Ez nem feltétlenül baj. A -m esetén a bemeneti match-elő sorok számát korlátozod, így egy sort ír ki akkor is, ha abban többször van meg a pattern, mint 1.
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
Kipróbáltam, csak sorokra igaz és nem a soron belül.
- A hozzászóláshoz be kell jelentkezni
Nem olyan nehéz ez. Az elképzelhető legtágabb illeszkedés fog érvényre jutni. Habár az 'aaaa' illeszkedik az 'a+'-ra, elegendő csupán 3 'a'-ra azt mondani, hogy illeszkedik, utána csak az 'ab'-kat nézni. Ily módon illeszkedik az 'abababab' az '(ab)*'-ra, de ismét elegendő csupán 3 'ab'-ra ráhúzni a regexet. Az utána következő 'abc'-k már az '(abc)*'-ra fognak illeszkedni.
A következő ábra alapján már triviális lesz:
a+ | (ab)* | (abc)*
aaa| ababab| abcabcabc
Látható, hogy volt lehetőségünk a teljes sort kijelölni vele, tehát garantáltan az elképzelhető legtágabb illeszkedés jutott érvényre. A regexek világa gyönyörű! Nagyon szeretem.
- A hozzászóláshoz be kell jelentkezni
Ez eddig rendben, de a kérdés lényegére, vagyis a miértre nem válasz.
- A hozzászóláshoz be kell jelentkezni
A reguláris kifejezés az nem egy algoritmus leírás, amit balról-jobbra olvasva hajt végre valami interpreter, hanem egy halmaz leírása.
Az illesztés olyan szövegrészletet választ ki, ami benne van halmazban. Mivel ilyenből több is lehet, ezért röviden szólva a balszélső leghosszabbat választja ki.
Amikor már megvan az illeszkedés, akkor lehet elkezdeni foglalkozni a részletekkel, hogy a regexp melyik részlete, az illeszkedés pontosan mely betűihez illeszkedjen.
Szerintem.
- A hozzászóláshoz be kell jelentkezni
Szégyenszemre ms oldalt linkelek, mert googleban ez volt az első értelmesnek tűnő :D
http://msdn.microsoft.com/en-us/library/dsy130b4%28v=vs.110%29.aspx
- A hozzászóláshoz be kell jelentkezni
A kérdés az, hogy az a+ az négyre _kell_, hogy illeszkedjen, vagy elég 3-ra is, mivel van még keresendő egyezés.
Ha az a{4}(ab)*(abc)* is kiszínez mindent, akkor kezdj el aggódni szerintem :)
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
Ki lehet próbálni:
awk \
'BEGIN {
x="aaaababababcabcabc"
for (i=1;i<=length(x);i++)
{
y=substr(x,1,i)
match(y,/a+(ab)*(abc)*/)
print y
print substr(y,1,RLENGTH)
print
}
}'
- A hozzászóláshoz be kell jelentkezni
Eszerint is teljesen korrektül csinálja az awk: teljes hosszában nézi a patternt, azaz csak akkor áll meg a 4db a-nál, ha nincs mögötte olyan, ami match-elne a pattern további részével.
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
OK, hogy ez a kérdés, de mi a válasz?
Mert az látható, hogy az egrep parancs úgy gondolja, hogy elég 3-ra is, a C# meg úgy, hogy 4-re kell.
Kinek van igaza?
Definiálva van ez valahol, vagy aki kiértékeli a kifejezést, az szabadon választhat, hogy neki mi a szimpatikusabb?
- A hozzászóláshoz be kell jelentkezni
Ebben melyik rész válasz az előző kérdésre? Biztos benne van, de azért ez így elég sok szerintem.
- A hozzászóláshoz be kell jelentkezni
zamboriz meglehetősen velős hozzászólásában van a lényeg. Egy regexpnél a szabály az, hogy az első előfordulást fogja megtalálni. Kedves példa rá:
$ echo zabaabaaab | sed -E 's/a*/X/'
Xzabaabaaab
$ echo zabaabaaab | sed -E 's/a+/X/'
zXbaabaaab
Ellenben ha adott pozícióban többféle hosszúságban lehet találni, akkor ebből a pozícióból kiindulva a lehető leghosszabbat fogja kiválasztani. Az, hogy a RE egyes részei hol fejeződnek be és hol kezdődnek a megtalálásnál, az csak a legvégén dől el. Ezt grep-pel még színezéssel sem igazán lehet kimutatni (mert kicsit másént viselkedik, mint az néhányaknak logikus lenne), de pl. sed-del igen.
$ echo aaaababababcabcabc | sed -E 's/a+/X/'
Xbabababcabcabc
$ echo aaaababababcabcabc | sed -E 's/a+(ab)*(abc)*/X/'
X
$ echo aaaababababcabcabc | sed -E 's/a{4}(ab)*(abc)*/X/' # Pty javaslata
Xbabababcabcabc
- A hozzászóláshoz be kell jelentkezni
Tehát akkor (utalva a nyitó poszt által felvetett kérdésre) kijelenthető, hogy a MS rosszul implementálta a C#-ban és a VStudioban a regexp kiértékelését?
--
PtY - www.onlinedemo.hu
- A hozzászóláshoz be kell jelentkezni
Erre kategorikus választ csak az tud adni, aki az MS-féle regexp definícióját ismeri. Amit én(*) mondtam, az - tudtommal - a UNIX/Linux világban használatos, az OpenGroup.org -on szereplő (általában POSIX-szabványként aposztrofált) leírás - szerintem - rövid, emberi nyelvre fordított verziója. De ha valaki mutat egy pár soros C# kódot, ami a kezdő felvetésben szereplő szringekkel és regexpekkel operálva kiírja az eredeti sztringet, majd a RE-vel meghatározott részt ebből a sztringből lecseréli X-re és azt is kiírja (ahogyan mondjuk itt én a sed-del tettem), akkor könnyedén eldönthető, hogy ugyanazt az eredményt kapjuk-e.
(Ja, ha valaki esetleg eltűnődött volna: a sed alapból BRE-t, és nem ERE-t használ, viszont van a GNU-sednek van egy dokumentált -r opciója az ERE-hez. Itt pedig azt is leírtam, hogy miért használom ennek ellenére következetesen a -E opciót erre. Mert hordozhatóbb :-) )
(*) itt konkrétan zamboriz mondta legfrappánsabban
Szerk: tényleg, milyen jó lnne egy C#-ban megírt sed (nyilván bőven elég lenne a sed s-parancsát implementálni)
- A hozzászóláshoz be kell jelentkezni
PS C:\> "zabaabaaab" -replace "a*","X"
XzXXbXXbXXbX
PS C:\> "zabaabaaab" -replace "a+","X"
zXbXbXb
PS C:\> "aaaababababcabcabc" -replace "a+","X"
XbXbXbXbcXbcXbc
PS C:\> "aaaababababcabcabc" -replace "a+(ab)*(abc)*","X"
XbXbXbXbcXbcXbc
PS C:\> "aaaababababcabcabc" -replace "a{4}(ab)*(abc)*","X"
Xbabababcabcabc
PS C:\>
Lehet elemezni. :)
- A hozzászóláshoz be kell jelentkezni
Az elsőre látszik rajta, hogy valami mucsajröcsögei nyelvjárást beszél, nem POSIX-et. Ez amúgy powershell akar lenni, vagy mi a szösz? Esetleg nincs neki -replace -eager vagy -replace -not-so-eager verziója? Esetleg az -eager mellett mondjuk -only-the-first opciója? Mindenesetre a *-ot eléggé nem a *X-világban megszokott módn értelmezi. Esetleg megmutatod ugyanezt "a{3}(ab)*(abc)*" mintával is?
Szerk:
PS C:\> "zabaabaaab" -replace "a*","X"
XzXXbXXbXXbX
némi fejvakarás után ez a legelső példa minősül a legdurvábbnak. Egyszerűen nem értem, a végére miért tesz még egy "X"-et. Meg az első 2 "a"-t miért 2 "X"-re cseréli, ha utána a 3 db "a"-t szintén. Mi lenne 4 db "a"-ból? És ha beleraksz egy plusz "c"-t a legvégére, akkor lesz "X" a "b" és a "c" között? Megannyi gyötrő kérdés, de azt így látatlanban le merném fogadni, hogy aki implementálta, az nem értette a POSIX-regexpeket :-) - vagy csak simán te szórakozol.
- A hozzászóláshoz be kell jelentkezni
Tényleg powershell, és ördögöd van, a végére bökött c hatására az eredmény vége bXcX.
Azt is jól sejted (illetve kérdezed elképedve), hogy tényleg mindig az összes előfordulást (sőt, itt még az előfordulatlanságot is) cseréli-e. Legalábbis a 2.0-ásban, amikor utoljára használni mertem a -replace operátort, még mindent-vagy-semmit volt a jelszó. Ha jól emlékszem, amikor az ember visszafogottságra vágyik, akkor közvetlenül kell példányosítania a .NET regex osztályából (vagy tán annak a szülőosztályából), mert a PS-be kötött része el van cseszve as designed sajátos.
A fenti hajmeresztést egyébként még nem szúrtam ki, de tényleg létezik. És non-greedysítve se normálisabb:
PS C:\> "zabaabaaab" -replace "a*?","X"
XzXaXbXaXaXbXaXaXaXbX
Magánvéleményem: ahol a MS magának találhatta ki a funkciókat, egész korrekt a PS, ahol szabályt kellett követnie, ott a partner szkriptinggájok vért izzadnak, hogy úgy tudják megfogalmazni az oktatóanyagokat, hogy véletlenül se kerüljön beléjük az alapvető hiba és a következmények. Az MS-only kollégák pedig csak elvétve veszik észre/teszik szóvá, hogy valami itten hiányzik, vagy mintha nem így kéne működnie.
- A hozzászóláshoz be kell jelentkezni
Itt írja, hogy milyen opciók vannak. Powershell replaceből (ami egy operátor amúgy) csak az inline modifiers érhetőek el.
Azt a mintát konkrétan végigvittem fejben, szerintem valahogy úgy értelmezi, hogy keressük meg az első match-t, csináljunk replace-t, folytassuk az előző match végétől amíg a string végére nem érünk. Azaz (a # jelöli az a{0}-t, a | hogy honnan keresi a következő match-t):
"zabaabaaab" = "|#z#a#b#a#a#b#a#a#a#b#" -> "X|z#a#b#a#a#b#a#a#a#b#" -> "XzX|#b#a#a#b#a#a#a#b#" -> "XzXX|b#a#a#b#a#a#a#b#" -> "XzXXbX|#b#a#a#a#b#" -> "XzXXbXX|b#a#a#a#b#" -> "XzXXbXXbX|#b#" -> "XzXXbXXbXX|b#" -> "XzXXbXXbXXbX|" = "XzXXbXXbXXbX"
- A hozzászóláshoz be kell jelentkezni
Itt nézegettem, a + és a * a kiértékelés sorrendjén változtat szerintem.
(a+)((ab)+)((abc)+)
Itt olyan mintha jobbról balra menne, abc-t, ab-t, a-t keresne, és így az egészre illeszkedik:
Array
(
[0] => aaaababababcabcabc
[1] => aaa
[2] => ababab
[3] => ab
[4] => abcabcabc
[5] => abc
)
(a+)((ab)*)((abc)*)
Ez meg balról jobbra, a-t, ab-t, abc-t keresne, ezért nem illeszkedik:
Array
(
[0] => aaaa
[1] => aaaa
[2] =>
[3] =>
[4] =>
)
(a+)((ba)*)((bca)*)
Viszont értelemszerűen illeszkedik (a, ba, bca a sorrend):
Array
(
[0] => aaaababababcabca
[1] => aaaa
[2] => bababa
[3] => ba
[4] => bcabca
[5] => bca
)
A miértre én sem tudom a választ.
(Szerk.: most látom hogy neked pont nem így van, akkor ez maga a kérdés volt, sorry. Az egrep mindkettőt végig kiszínezi, de akkor talán a jobbról balra dolog miatt lehet?)
- A hozzászóláshoz be kell jelentkezni
.
- A hozzászóláshoz be kell jelentkezni