Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Kifejezések


Reguláris kifejezések





     
A reguláris vagy szabályos kifejezések bizonyos szabályokat követő
karaktersorozatok. Arra szolgálnak, hogy megkönnyítsék a szöveggel való munkát,
mint a keresés, helyettesítés, ellenőrzés, stb. Az ilyen kifejezések sok programozási
nyelvbe be vannak építve, főleg a szövegek feldolgozására specializálódott
nyelvek, mint az XML vagy a HTML. A C++11 is szabványosította ezeket a
kifejezéseket a könyvtár révén. A reguláris kifejezések szabályai
eltérőek lehetnek, ezért több szabályzat 
(szintaxis) sorolható fel. Ezek közül a C++11 az ECMAScript, az alap és
bővített POSIX, az awk, a grep és az egrep szabálygyűjteményeit támogatja. A
következő példákban az ECMAScript szintaxisát fogjuk használni.





     
A reguláris kifejezéseket fokozatosan kell felépíteni, akár egy
programot. Először az alap dolgok működjenek, aztán jöhetnek a különböző
megszorítások:




  1. Legyen
    egy program, ami számokat fogad el bemenetnek. Az ECMAScript a számokat a
    [:digit:] vagy [:d:] szintaxissal azonosítja: regex r("[[:digit:]]");

  2. A
    fenti kifejezés csak egyjegyű számokat fogad el. Több számjegy esetén a végére
    kell írni egy + jelt: regex r("[[:digit:]]+");

  3. Ha
    tesztelni szeretnénk, hogy a beolvasott szám nem-e negatív, akkor a kifejezés
    elejébe a –? kombinációt kell tenni: regex r("-?[[:digit:]]+");

  4. Ha a
    felhasználó netán a + karaktert is használja a számok előtt, akkor erre is fel
    kell készíteni a fordítót, ugyanis ez egy speciális karakter az ECMAScript
    szintaxisában. Hogy figyelmen kívül hagyja ezt a karaktert, a \\+? jelt kell a
    kifejezés elejébe írni: regex r("(\\+?[[:digit:]]+");

  5. A
    kifejezés előtt lévő ellenőrzéseke kombinálni kell egy „vagy” kapuval, mert
    vagy az egyik, vagy a másik fordulhat elő: regex r("(\\+|-)?[[:digit:]]+");





Ezt a felépített kifejezést alkalmazzuk a
következő programban. Ha a bevitt számjegy nem felel meg a reguláris kifejezés
szabályainak, akkor a „Nem helyes!” üzenet jelenik meg. A program a q billentyű
beviteléig fut.





#include


#include


#include





using namespace std;





int main()


{


      string input;


      regex r("(\\+|-)?[[:digit:]]+");





      while(true) //végtelen ciklus


      {


            cout
"Irj be egy egesz szamot: "
;


            cin >>
input;


            if(input=="q")
break; // q esetén
kilép


            if(regex_match(input,r))


                  cout
"Helyes!"


            else


                  cout
"Nem helyes!"
endl;


      }


}





A reguláris kifejezés helyességét az std::regex_match() függvény ellenőrzi. A kimenet:





Irj be egy egesz
szamot: 23


Helyes!


Irj be egy egesz
szamot: +51


Helyes!


Irj be egy egesz
szamot: -79


Helyes!


Irj be egy egesz
szamot: 6.7


Nem helyes!


Irj be egy egesz
szamot: +-41


Nem helyes!


Irj be egy egesz
szamot: abc


Nem helyes!


Irj be egy egesz
szamot: q





Ha valós számokra is hasonlóképp kell
felépíteni a reguláris kifejezést. Ott a tizedespont utáni rész opcionális,
ezért a ([[:digit:]]+)? kifejezéssel jelöljük. Ugyanígy a tizedespont is
opcionális ha nincs utána semmi, így az egész második részt (\\.)? közé lehet
tenni:
regex rr("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?");





Ha a feladat, hogy tudományos formátumú
számokat lehessen beírni, mint pl. -1.23e+06 vagy 1E3, akkor azzal bővítjük az
előző kifejezést, hogy az exponenciális tag is opcionális részese lehet a
számnak. Az exponenciális részt a ((e|E)((\\+|-)?)[[:digit:]]+)? kifejezés
jelenti:
regex rrr("((\\+|-)?[[:digit:]]+)(\\.(([[:digit:]]+)?))?((e|E)((\\+|-)?)[[:digit:]]+)?");





Az alapértelmezettként használt ECMAScript
logikája hamar elsajátítható, de beállítható más szintaxis is, például a POSIX
grep:





#include


#include


#include





int main()


{


    std::string str = "zzxayyzz";


    std::regex re1(".*(xay)"); //
ECMAScript


    std::regex re2(".*(xay)", std::regex::grep); // POSIX grep





    std::cout "Kereses 'xay' utan az 'zzxayyzz' szovegben:\n";


    std::smatch m;


   
std::regex_search(str, m, re1);


    std::cout " ECMAScript: " '\n';


   
std::regex_search(str, m, re2);


    std::cout "
POSIX grep: "
'\n';


}





A fenti program egy keresést végez az str stringben. A keresést az std::regex_search() függvény végzi, melynek első paramétere egy string amiben a keresés
zajlik, a második egy konténer, ami a találatokat tartalmazza, a harmadik pedig
a keresés reguláris kifejezése. Az eredmény:





Kereses 'xayy'
utan az 'zzxayyzz' szovegben:


 ECMAScript: zzxay


 POSIX grep: zzxay





Raw stringek





A raw stringek olyan stringek, melyekben a
feloldójelek (pl. \n, \t, \) nem érvényesek. Szintaxisa: R”(szoveg)”. A
következő program jól szemlélteti a hagyományos és a raw string közti
különbséget:








#include


#include





using namespace std;





int main()


{


    string normal_str="Elso sor.\nMasodik sor.\nUzenet vege.\n";


    string raw_str=R"(Elso sor.\nMasodik sor.\nUzenet vege.\n)";


   
cout


   
cout


    return(0);


}





A kimenet:





Elso sor.


Masodik sor.


Uzenet vege.





Elso
sor.\nMasodik sor.\nUzenet vege.\n





A raw string egyik célja, hogy valamennyire
egyszerűsítse a reguláris kifejezések használatát. Ezzel közvetlen bevihetők az
ECMAScript kifejezések anélkül, hogy a feloldójeleket a fordító felismerné. Egy
korábbi példában a bemenő számok helyességét a következőképp ellenőriztük:





regex r("(\\+|-)?[[:digit:]]+");





Ugyanez raw stringgel:





regex integer(R"((\+|-)?[[:digit:]]+)");





Lambda függvények és
kifejezések





A reguláris kifejezések és a raw stringek
mellett egy másik hasznos nyelvezet a lambda. A lambda kifejezések lehetővé
teszik, hogy a név nélkül definiáljunk és használjunk függvényeket. Használható
a függvényobjektumok helyett, így nem kell külön osztályt és tagfüggvényt
definiálni. A következő lambda kifejezés egy olyan függvényt definiál, amelyik
egy számot térít vissza:





[]() -> int
{ return 4; }();





A fenti függvény igazából semmi hasznosat
nem tesz, csupán visszatéríti a 4-et, ami például kiírásra használható:





int result = []()
-> int { return
4; }();


cout





Kicsit hasznosabb a következő:





int result = [](int input) -> int
{ return 2 * input; }(10);


cout





A fenti kifejezésnek van agy bemenő paramétere
(input) és visszatéríti ennek dupláját. A függvény rögtön a deklarálás után
megkapja a 10 paramétert, így a kiírt érték 20. Hasonlóképp felírható két szám
összege:





int result = [](int a,int b) -> int { return a + b;
}(2,4);


cout





Akár a reguláris kifejezések, a lambda
kifejezések is kombinálhatók, egymásba építhetők:





int result = [](int m, int n) -> int { return m + n; }
([](int a) -> int
{ return a; }(2),[](int
a) -> int { return
a; }(3));


cout





A fenti lambda függvényben két másik lambda
függvény szerepel, egyik 2-t, másik 3-at térít vissza, a fő függvény pedig
összeadja ezeket, mint bemenő paramétereket. A függvénymutatók működnek a
lambda függvényekre is:





auto func = [](int a, int b) -> int { return a+b; };


cout





Az auto típus a func változót a lambda
kifejezésre mutató mutatóként fogja deklarálni. Tegyük fel, hogy egész
számokkal megpakolt vektor tartalmát kell rendezni a sort() algoritmussal. Ez a
hagyományos C++98 fordítóval a következőképp néz ki:





#include


#include


#include





bool compare(int i,int j)


{


      return (i


}





using namespace std;





int main()


{


      vectorint> v {3,1,7,4,8,9,5,6,2,10};


      for(int i = 0; i v.size(); i++) cout "
"
; cout


      sort(v.begin(),
v.end(), compare); //rendezés


      for(int i = 0; i v.size(); i++) cout "
"
; cout





      return 0;


}





Lambda kifejezéssel ugyanez elérhető,
megspórolva a compare() függvény deklarálását:





sort(v.begin(), v.end(), [](int i, int j) -> bool{ return (i j);}); //rendezés








Függvénymutatók





A függvénymutatók is a programozás
egyszerűsítésére szolgálnak. Egy függvény nem más, mint egy memóriacím, ahonnan
az utasítások kezdődnek. A függvény hívásához elegendő ezt a címet ismerni.





A következő függvénymutató olyan
függvényre mutat, melynek paramétere két
char, visszatérített típusa pedig int. A mutató
neve
func, amit bármilyen
függvényhez lehet használni, melynek ilyen a felépítése.





      int (*func)(char,char) = NULL;





A függvénymutatók az osztályok
tagfüggvényeire is mutathatnak.





      int (MyClass::*Classfunc)(char,char) = NULL;





Mindkét mutató NULL mutatónak van
inicializálva, de lehet rögtön a függvény címét is adni (pl.
&fuggveny). Ha a mutató megkapta a függvény címét,
a függvény rajta keresztül hívható:





int result = func(10,2);


int result =
(obj.*Classfunc)(10,2);





Mivel mutatóról van szó, ez paraméterként
is átadható egy másik függvénynek.





void PassPtr(int (*funcptr)(char, char))


{


   int result =
(*funcptr)(20,3);     // call using function pointer


   cout "PassPtr:
"


}





A függvényt a következőképp lehet
meghívni:
PassPtr(func);





A függvénymutató egy függvény
visszatérített értéke is lehet:





int
(*ReturnPtr(char muvelet))(char, char)


{


   if(muvelet
== '+')


      return
&Plus;


   else


      return
&Minus;


}





Ebben az esetben a Plus() és Minus() két hasonló függvény. A következő példában
összesítve vannak az eddig felsorolt példák:







This post first appeared on Altair Gate - News, please read the originial post: here

Share the post

Kifejezések

×

Subscribe to Altair Gate - News

Get updates delivered right to your inbox!

Thank you for your subscription

×