2016. október 4., kedd

Stringek

      A basic_string osztálysablon sok olyan alapfunkciót tartalmaz ami a karakterláncok feldolgozásához szükséges, mint például a törlés vagy a keresés. Mindez a namespace std-ben van definiálva és ugyanitt található a typedef basic_string<char> string deklaráció is, amely a string álnevet adja a basic_string<char> -nek. Egy string objektum létrehozható például a string s1("Hello") utasítással, amely létrehoz egy string objektumot egy const char* típusból, amely a Hello karaktereket tartalmazza a \0 terminátort leszámítva. A char* típusú karakterláncoktól eltérően a string objektumok nem kell tartalmazzák a NULL-t az utolsó pozíción. Ha az objektumot a string s1(8, ’x’) utasítással hozzuk létre, akkor az 8 darab x karakter fog tartalmazni. Ezek mellett a string rendelkezik még implicit konstruktorral és egy másoló konstruktorral is.

Stringek értékadása és összefűzése
      A referenciákkal létező változókra hivatkozunk, ezért minden referencia deklarálásnál rögtön meg is kell határozni (inicializálni kell), hogy mire megy a hivatkozás:

#include <iostream>
using std::cout;
using std::endl;
#include <string>
using std::string;

int main()
{
     string s1("cat"), s2, s3;
    
     s2 = s1;        //értékadás
     s3.assign(s1);  //értékadás assign()-el
     cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3 << "\n\n";
    
     s2[0] = s3[2] = 'r';
     cout << "s2[0] = s3[2] = 'r':\n" << "s1: " << s1 << "\ns2: " << s2 << "\ns3: ";
     int len = s3.length();
     for(int x = 0; x < len; ++x)
           cout << s3.at(x);
          
     string s4(s1 + "apult"), s5; // s4=s1+apult, s5=""
     s3 += "pet";                 // s3=s3+pet
     s1.append("acomb");          // s1=s1+"acomb"
     s5.append(s1, 4, s1.size()); // s5=s1-cata
     cout << "\n\nÖsszefűzés után:\n" << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3 << "\ns4: " << s4 << "\ns5: " << s5 << endl;
    
     return 0;
}

A kimenet:
s1: cat
s2: cat
s3: cat

s2[0] = s3[2] = 'r':
s1: cat
s2: rat
s3: car

Összefűzés után:
s1: catacomb
s2: rat
s3: carpet
s4: catapult
s5: comb

Az s2 = s1 utasítás két objektum között tesz egyenlőséget, s2 az s1 másolata lesz. Ugyanez teszi az assign() függvény is, s3 lesz az s1 másolata. A [] operátorral elérhetőek a string elemei, az at() függvény emellett leellenőrzi az index korlátait is. Az append()függvény a karakterláncok összefűzését valósítja meg. Az s5.append(s1, 4, s1.size()) utasítás hozzáfűzi s5-höz az s1 negyedik pozíciójától számított karaktereket.

Substringek
      A string osztály substr függvénye lehetővé teszi egy substring kivételét a stringből.

#include<iostream>
using std::cout;
#include <string>
using std::string;

int main()
{
     string s("The airplane flew away.");
     cout << s.substr(7,5);
     return 0;
}

A kimenet:
plane

A s.substr(7,5) utasítás kiveszi a 7 és 5 pozíciók közti substringet téríti vissza az s-ből.

A string objektumok tulajdonságai
      A string osztálynak egyes függvényei információt szolgáltatnak a karakterláncról, mint a hosszúság, maximális hosszúság és kapacitás. A string hossza az objektumban lévő karakterek pillanatnyi száma. A kapacitás az a legnagyobb szám, amit még a string eltárolhat anélkül, hogy megnőne a számára lefoglalt memória. A maximális hossz a string objektumnak lefoglalható legnagyobb memória.

#include <iostream>
using std::cout;
using std::cin;
#include <string>
using std::string;

void printStats(const string&);

int main ()
{
     string s;
     cout << "Statisztikák a beolvasás előtt:\n";
     printStats(s);
     cout << "\n\nOlvass be egy stringet: ";
     cin >> s;
     cout << "A beolvasott string: " << s << "\nStatisztikák a beolvasás után:\n";
     printStats(s);
     s.resize(s.length()+10);
     cout << "\n\nResize után (length+10):\n";
     printStats(s);
     s.append("addition");
     cout << "\nA beolvasott string: " << s;
     return 0;
}
void printStats(const string& str)
{
     cout << "Kapacitás: " << str.capacity()
          << "\nMax hosszúság: " << str.max_size()
          << "\nHosszúság: " << str.size()
          << "\nÜres? " << (str.empty() ? "igen" : "nem");
}

A kimenet:
Statisztikák a beolvasás előtt:
Kapacitás: 0
Max hosszúság: 4611686018427387897
Hosszúság: 0
Üres? igen

Olvass be egy stringet: onceuponatime
A beolvasott string: onceuponatime
Statisztikák a beolvasás után:
Kapacitás: 16
Max hosszúság: 4611686018427387897
Hosszúság: 13
Üres? nem

Resize után (length+10):
Kapacitás: 32
Max hosszúság: 4611686018427387897
Hosszúság: 23
Üres? nem
A beolvasott string: onceuponatime          addition

A program deklarál egy string objektumot, amely eleinte üres. A karakterlánc beolvasása után a printStats() függvény 13 hosszúságot ír ki, amit a beolvasott karakterek számára utal. A karakterlánc számára lefoglalt kapacitás egyenlő az ehhez legközelebb álló kettő hatványával, 16-tal. A hosszúság növelése automatikusan megnöveli a kapacitást is. A hosszúságnövelés üres karakterek beszúrását jelenti.

Keresés a stringben

#include <iostream>
using std::cout;
#include <string>
using std::string;

int main()
{
     //a fordító egyetlen stringgé alakítja a tördelt szöveget
     string s("Egy baloldali részfa elemei "
              "\nkisebbek, mint a csúcs elemei"
              "\nés a jobboldali részfa elemei"
              "\nnagyobbak, mint a csúcs elemei.");
     cout << "Az eredeti szöveg:\n" << s;
     //a "részfa" substring keresése
     cout << "\n\nAz első \"részfa\" kezdete: " << s.find("részfa");
     cout << "\nAz utolsó \"részfa\" kezdete: " << s.rfind("részfa");
     //a 'z' karakter keresése
     cout << "\nAz első karakter \"qpxz\"-ből: " << s.find_first_of("qpxz");
     cout << "\nAz utolsó karakter \"qpxz\"-ből: " << s.find_last_of("qpxz");
     //a '-' karakter keresése
     cout << "\nAz első karakter amely nincs benne a \"dntusbgmcvp\"-ben: "
          << s.find_first_not_of("dntusbgmcvp");
     //a '\n' karakter keresése
     cout << "\nAz utolsó karakter, amely nincs benne a \"dntusbgmcvp\"-ben: "
          << s.find_last_not_of("dntusbgmcvp");
    
     return 0;
}

A kimenet:
Az eredeti szöveg:
Egy baloldali részfa elemei
kisebbek, mint a csúcs elemei
és a jobboldali részfa elemei
nagyobbak, mint a csúcs elemei.

Az első "részfa" kezdete: 14
Az utolsó "részfa" kezdete: 75
Az első karakter "qpxz"-ből: 17
Az utolsó karakter "qpxz"-ből: 78
Az első karakter amely nincs benne a "dntusbgmcvp"-ben: 0
Az utolsó karakter, amely nincs benne a "dntusbgmcvp"-ben: 119

A main függvényben deklarálva és inicializálva van az s objektum. A fordító mind a 4 sort összefűzi még mielőtt a program elindulna. Az s.find("reszfa") utasítás visszatéríti a reszfa szó kezdő pozícióját az s stringben. Ha nem találja, akkor a string::npos konstanst téríti vissza. Az s.rfind("reszfa") utasítás a legutolsó reszfa szó kezdő pozícióját téríti vissza. Az s.find_first_of("qpxz") függvény megkeresi s-ben a gpxz bármely karakterének első előfordulási helyét. Az s.find_last_of("qpxz") függvény ugyanígy az utolsó előfordulási helyet kutatja. Az s stringben a z az amit megtalál a gpxz substringből. A s.find_first_not_of("dntusbgmcvp") utasítás azt az első olyan karaktert keresi s-ben, amely nem része a dntusbgmcvp substringnek.  A s.find_last_not_of("dntusbgmcvp") pedig az utolsó olyan karaktert keresi amely nem része ennek.

Karakterek behelyettesítése

#include <iostream>
using std::cout;
#include <string>
using std::string;

int main()
{
     string s("Egy baloldali rőszfa elemei "
              "\nkisebbek, mint a csúcs elemei"
              "\nés a jobboldali részfa elemei"
              "\nnagyobbak, mint a csúcs elemei.");

     s.erase(62);                 //mindent kitöröl 62-től
     cout << "A törles utan:\n" << s;

     int x = s.find(" ");         //megkeresi az első szóközt  
     while(x != string::npos)     //amíg nincs vége a stringnek
     {
           s.replace(x, 1, ".");  //addig kicseréli a szóközt pontra
           x=s.find(" ",x+1);     //és megkeresi a következő szóközt
     }
    
     cout << "\n\nA behelyettesítés után:\n" << s;

     return 0;
}

A kimenet:
A törles után:
Egy baloldali részfa elemei
kisebbek, mint a csúcs elemei
és

A behelyettesítés után:
Egy.baloldali.részfa.elemei.
kisebbek,.mint.a.csúcs.elemei
és.

Az s.erase(62) utasítás mindent kitöröl s-ből a 62. pozíciótól a string végéig. Az s.replace(x, 1, ".") utasítás első paramétere a keresett pozíció, a második helyettesíteni kívánt karakterek száma, az utolsó pedig a helyettesítő karakter. A a string::npos string maximális hosszát jelenti. Amikor a find függvény ezt téríti vissza, akkor elérkezett a string végéhez.

Karakterek beszúrása

#include <iostream>
using std::cout;
#include <string>
using std::string;

int main()
{
     string s1("Eleje vége"),s2("közepe "), s3("12345678"), s4("xx");
    
     cout << "Kezdeti stringek:\ns1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3 << "\ns4: " << s4 << "\n\n";
     s1.insert(6, s2); // beteszi a "közepe" szót az s1 6. pozíciójára
     s3.insert(3, s4, 0, string::npos);  // beteszi az "xx" szót az s3 3. pozíciójára
     cout << "Beszúrás után:\ns1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3     << "\ns4: " << s4;
    
     return 0;
}

A kimenet:
Kezdeti stringek:
s1: Eleje vége
s2: közepe
s3: 12345678
s4: xx

Beszúrás után:
s1: Eleje közepe vége
s2: közepe
s3: 123xx45678
s4: xx

Az s1.insert(6, s2) utasítás beteszi s1-be az s2 stringet a 6. pozíció elé. Az s3.insert(3, s4, 0, string::npos) utasítás  az s3-ba teszi be az s4 stringet a 3. pozíció elé. Az utolsó két argumentum a kezdeti pozíciót a karakterek számát jelentik amit az s4-ből ki kell olvasni.

Iterátorok

A string osztály iterátorokkal is rendelkezik, melyekkel előre-hátra bejárható a string. Külön hozzáférést adnak mindenik karakterhez és a szintaxisuk hasonló a mutatókéhoz.

#include <iostream>
using std::cout;
#include <string>
using std::string;

int main()
{
     string s("Iterátorok tesztelése");
     string::const_iterator i1 = s.begin();
     cout << "s = " << s << "\nAz i1 iterátorral: ";
     while(i1 != s.end())
     {
           cout << *i1;
           ++i1;
     }
    
     return 0;
}

A kimenet:
s = Iterátorok tesztelése
Az i1 iterátorral: Iterátorok tesztelése

Az s.begin() utasítás egy iterátort térít vissza, amely s első pozíciójára mutat. Ezt addig lehet növelni, amíg el nem éri az s.end() iterátort, ami az s végére mutat. Az iterátor dereferenciálásával (a mutatott értékre való hivatkozásával) kiírható az aktuális karakter.

A stream-ek feldolgozása

A standard és a könyvtár I/O streamek mellett a C++ lehetőséget ad a stringek memóriába való bevitelére és kiolvasására. A stringek bevitelét az istringstream osztály, a kiolvasását az ostringstream osztály támogatja. Ezek tolajdonképpen álnevek a következőkre:
typedef basic_istringstream<char> istringstream;
typedef basic_ostringstream<char> ostringstream;
A basic_istringstream és a basic_ostringstream osztályok funkciója ugyanaz mint az istream és ostream osztályoké, melyek tartalmaznak még néhány memóriakezelő függvényt. Azok a programok melyek a memóriánam formálják meg az adatfolyamokat, tartalmazniuk kell az <sstream> és <iostream> headereket. Ezek egyik alkalmazása az adatok hitelesítése. A program ugyanis első fázisként beolvashatja az adatokat egy stringbe, ami után megtörténik a hitelesítés és ha szükséges akkor a hibajavítás is. Ezután a program nyugodtan dolgozhat a stringgel tudván, hogy annak formátuma helyes. A string objektumot elő lehet készíteni a képernyőre való kiírásra majd el lehet tárolni. Az ostringstream osztály a string objektumot arra használja, hogy eltárolja azokat az adatokat, amelyeket ki kell majd írni a képernyőre. Az osztály str tagfüggvénye egy string típusú másolatot készít az objektum tartalmáról.

#include <iostream>
using std::cout;
#include <string>
using std::string;
#include <sstream>
using std::ostringstream;

int main()
{
     string s1("Néhány adattípus beszúrva "),
            s2("egy ostringstream-be:"),
            s3("\ndouble: "),
            s4("\nint: "),
            s5("\az int címe: ");
     double d = 123.4567;
     int i = 22;
     ostringstream outputString;
    
     outputString << s1 << s2 << s3 << d << s4 << d << s5 << &i;
    
     cout << "Az outputString tartalma:\n" << outputString.str();
     outputString << "\nutólag hozzáadott karakterek.";
    
     cout << "\n\nA stream-be való beszúrás után:\n" << outputString.str();

     return 0;
}

A kimenet:
Az outputString tartalma:
Néhány adattípus beszúrva egy ostringstream-be:
double: 123.457
int: 123.457
az int címe: 0x22fdcc

A stream-be való beszúrás után:
Néhány adattípus beszúrva egy ostringstream-be:
double: 123.457
int: 123.457
az int címe: 0x22fdcc
utólag hozzáadott karakterek.

Az istringstream objektum betölti egy stringből az adatokat a memóriába. Az adatok karakterként vannak tárolva. Az istringstream objektumok beolvasása hasonló a standard vagy a fájlba való beolvasáshoz. A string objektum végét az istringstream objektumok end-of-file-nak értelmezi.

#include <iostream>
using std::cout;
#include <string>
using std::string;
#include <sstream>
using std::istringstream;

int main()
{
     string input("Input test 123 4.7 A");
     string string1, string2;
     int i;
     double d;
     char c;
     istringstream inputString(input);

     inputString >> string1 >> string2 >> i >> d >> c;
    
     if(inputString.good())
           cout << "\nAz inputString nem üres.\n";
     else
           cout << "\nAz inputString üres.\n";

     cout << "Az istringstream objektumból\n"
          << "a következő elemeket vettem ki:"
          << "\nstring: " << string1
          << "\nstring: " << string2
          << "\nint: " << i
          << "\ndouble: " << d
          << "\nchar: " << c;
            
     inputString >> string1;
    
     if(inputString.good())
           cout << "\nAz inputString nem üres.\n";
     else
           cout << "\nAz inputString üres.\n";
          
     return 0;
}

A kimenet:
Az inputString nem üres.
Az istringstream objektumból
a következő elemeket vettem ki:
string: Input
string: test
int: 123
double: 4.7
char: A
Az inputString üres.

Az input egy string objektum, amely a Input test 123 4.7 A szöveggel van inicializálva. Ezeket a szavakat az inpuString átveszi, majd átrakja különböző változókba. Ezek után az inputString újból megpróbál felvenni az input objektumból egy szót, de ez már nem lehetséges, mert már egyszer kiírta tartalmát a cout-tal. Az inputString nem vehet fel új értékeket.