String
, contenuta nella libreria standard
string
10.4. Noi
tuttavia preferiamo reinventare la ruota, costruendo una nostra classe
Stringa
, che meglio si adatta agli scopi didattici di questo corso.
Implementeremo una Stringa
con un array dinamico di caratteri e, oltre
alla sovrapposizione degli operatori basilari (entrata, uscita,
concatenazione), a titolo di esempio programmeremo alcune
funzioni di utilità generale per una stringa, come la ricerca di
sottostringhe e il conteggio di ricorrenze di caratteri in una stringa.
// stringa.h // implementa un tipo stringa di caratteri // le seguenti macro servono ad evitare inclusioni // multiple del presente file di intestazione #ifndef _STRINGA_H_ #define _STRINGA_H_ const unsigned int MAX_LUNGHEZZA = 100; #include <iostream.h> class Stringa { // funzioni friend per gestire l'i/o di stringhe friend ostream& operator<< (ostream&, const Stringa&); friend istream& operator>> (istream&, Stringa&); // funzioni friend per la sovrapposizione di operatori binari // concatenazione di stringhe friend Stringa operator+ (const Stringa& s1, const Stringa& s2); friend Stringa operator+ (const char* s1, const Stringa& s2); friend Stringa operator+ (const Stringa& s1, const char* s2); // eliminazione degli ultimi n caratteri di una stringa friend Stringa operator- (const Stringa& s, unsigned int n); // operatori di confronto friend bool operator== (const Stringa& s1, const Stringa& s2); friend bool operator< (const Stringa& s1, const Stringa& s2); friend bool operator> (const Stringa& s1, const Stringa& s2) { if (!(s1 < s2) && !(s1 == s2)) return true; return false; } friend bool operator<= (const Stringa& s1, const Stringa& s2) { if (s1 < s2 || s1 == s2) return true; return false; } friend bool operator>= (const Stringa& s1, const Stringa& s2) { if (!(s1 < s2)) return true; return false; } friend bool operator!= (const Stringa& s1, const Stringa& s2) { if (!(s1 == s2)) return true; return false; } public: // costruttore default Stringa (const char* s = 0); // costruttore di copia Stringa (const Stringa&); // sovrapposizione dell'operatore di assegnamento const Stringa& operator= (const Stringa&); // distruttore ~Stringa (); // sovrapposizione di alcuni operatori comuni // concatena una nuova stringa alla preesistente Stringa& operator+= (const char* s); Stringa& operator+= (const Stringa&); // elimina gli ultimi n caratteri dalla stringa Stringa& operator-= (unsigned int n); // crea una stringa formata da n ripetizioni // della stringa preesistente Stringa& operator*= (unsigned int n); // funzioni di utilita` // ritorna la lunghezza della stringa (senza '\0') unsigned int lunghezza () const { return len; } // operatore di conversione a const char* operator const char* () const { return stringa; } // conversioni MAIUSCOLO <--> minuscolo Stringa& maiuscolo (); Stringa& minuscolo (); // inverte la stringa Stringa& inverti (); // ricerca di una sottostringa int trova (const Stringa&) const; // estrazione sinistra di una sottostringa // ritorna la sottostringa estratta Stringa estrai (unsigned int pos, unsigned int lung); // conteggio di una stringa ricorrente unsigned int conta (const Stringa&) const; private: char* stringa; unsigned int len; }; #endif // _STRINGA_H_
// stringa.cpp #include "stringa.h" #include <string.h> Stringa::Stringa (const char* s) { if (s == 0) { len = 0; stringa = 0; } else { len = strlen(s); stringa = new char[len + 1]; for (int i = 0; i < len; i++) stringa[i] = s[i]; stringa[len] = '\0'; } } Stringa::Stringa (const Stringa& s) { len = s.len; if (s.stringa == 0) stringa = 0; else { stringa = new char[len + 1]; for (int i = 0; i < len; i++) stringa[i] = s[i]; stringa[len] = '\0'; } } const Stringa& Stringa::operator= (const Stringa& s) { // evita l'autoassegnamento if (&s != this) { if (len != s.len) { len = s.len; delete[] stringa; stringa = new char[len + 1]; } for (int i = 0; i < len; i++) stringa[i] = s[i]; stringa[len] = '\0'; } return *this; } Stringa::~Stringa () { delete[] stringa; } Stringa& Stringa::operator+= (const char* s) { if (s != 0) { // crea una copia temporanea di back up Stringa tmp(*this); int i; // contatore len += strlen(s); delete[] stringa; stringa = new char[len + 1]; for (i = 0; i < tmp.len; i++) stringa[i] = tmp.stringa[i]; for (i = 0; i < strlen(s); i++) stringa[i + tmp.len] = s[i]; stringa[len] = '\0'; } return *this; } Stringa& Stringa::operator+= (const Stringa& s) { if (s.stringa != 0) { // crea una copia temporanea di back up Stringa tmp(*this); int i; // contatore len += s.len; delete[] stringa; stringa = new char[len + 1]; for (i = 0; i < tmp.len; i++) stringa[i] = tmp.stringa[i]; for (i = 0; i < s.len; i++) stringa[i + tmp.len] = s.stringa[i]; stringa[len] = '\0'; } return *this; } Stringa& Stringa::operator-= (unsigned int n) { if (len > n) { // crea una copia temporanea di back up Stringa tmp(*this); delete[] stringa; len -= n; stringa = new char[len + 1]; for (int i = 0; i < len; i++) stringa[i] = tmp.stringa[i]; stringa[len] = '\0'; } else { delete[] stringa; stringa = 0; len = 0; } return *this; } Stringa& Stringa::operator*= (unsigned int n) { if (n > 1) { // crea una copia temporanea di back up Stringa tmp(*this); delete[] stringa; len *= n; stringa = new char[len + 1]; for (int i = 0; i < len; i++) stringa[i] = tmp.stringa[i % tmp.len]; stringa[len] = '\0'; } return *this; } Stringa& Stringa::minuscolo() { for (int i = 0; i < len; i++) if (stringa[i] >= 65 && stringa[i] <= 90) stringa[i] += 32; return *this; } Stringa& Stringa::maiuscolo() { for (int i = 0; i < len; i++) if (stringa[i] >= 91 && stringa[i] <= 116) stringa[i] -= 32; return *this; } Stringa& Stringa::inverti() { if (stringa != 0) { for (int i = 0; i < len / 2; i++) { char tmp = stringa[i]; stringa[i] = stringa[len - i - 1]; stringa[len - i - 1] = tmp; } } return *this; } int Stringa::trova (const Stringa& s) const { if (len > s.len) { for (int i = 0; i < len - s.len; i++) { bool uguale = true; for (int j = 0; j < s.len; j++) if (stringa[i + j] != s.stringa[j]) uguale = false; if (uguale == true) return i; } } else if (s.len == len) if (s == *this) return 0; return -1; } Stringa Stringa::estrai (unsigned int pos, unsigned int lung) { Stringa tmp; if (lung < len) { tmp.len = lung; tmp.stringa = new char[tmp.len + 1]; for (int i = 0; i < lung; i++) tmp.stringa[i] = stringa[i+pos]; } return tmp; } unsigned int Stringa::conta (const Stringa& s) const { int r = 0; // ricorrenze trovate if (s.stringa != 0) { for (int i = 0; i < len - s.len; i++) { bool uguale = true; for (int j = 0; j < s.len; j++) if (stringa[i + j] != s.stringa[j]) uguale = false; if (uguale == true) r++; } } return r; } Stringa operator+ (const Stringa& s1, const Stringa& s2) { Stringa tmp; int i; // variabile contatore tmp.len = s1.len + s2.len; tmp.stringa = new char[tmp.len + 1]; for (i = 0; i < s1.len; i++) tmp.stringa[i] = s1.stringa[i]; for (i = 0; i < s2.len; i++) tmp.stringa[s1.len + i] = s2.stringa[i]; tmp.stringa[s1.len + s2.len] = '\0'; return tmp; } Stringa operator+ (const Stringa& s1, const char* s2) { Stringa tmp; int i; // variabile contatore tmp.len = s1.len + strlen(s2); tmp.stringa = new char[tmp.len + 1]; for (i = 0; i < s1.len; i++) tmp.stringa[i] = s1.stringa[i]; for (i = 0; i < strlen(s2); i++) tmp.stringa[s1.len + i] = s2[i]; tmp.stringa[s1.len + strlen(s2)] = '\0'; return tmp; } Stringa operator+ (const char* s1, const Stringa& s2) { Stringa tmp; int i; // variabile contatore tmp.len = strlen(s1) + s2.len; tmp.stringa = new char[tmp.len + 1]; for (i = 0; i < strlen(s1); i++) tmp.stringa[i] = s1[i]; for (i = 0; i < s2.len; i++) tmp.stringa[strlen(s1) + i] = s2.stringa[i]; tmp.stringa[strlen(s1) + s2.len] = '\0'; return tmp; } Stringa operator- (const Stringa& s, unsigned int n) { Stringa tmp; if (s.len > n) { tmp.len = s.len - n; tmp.stringa = new char[tmp.len + 1]; for (int i = 0; i < tmp.len; i++) tmp.stringa[i] = s.stringa[i]; tmp.stringa[tmp.len] = '\0'; } return tmp; } bool operator== (const Stringa& s1, const Stringa& s2) { if (s1.len == s2.len) { for (int i = 0; i < s1.len; i++) if (s1.stringa[i] != s2.stringa[i]) return false; return true; } return false; } bool operator< (const Stringa& s1, const Stringa& s2) { int min; if (s1.len <= s2.len) min = s1.len; else min = s2.len; for (int i = 0; i < min; i++) { if (s1.stringa[i] < s2.stringa[i]) return true; } return false; } ostream& operator<< (ostream& os, const Stringa& s) { if (s.stringa != 0) os << (const char*)s; return os; } istream& operator>> (istream& is, Stringa& s) { char buffer[MAX_LUNGHEZZA + 1]; cin >> buffer; s = Stringa(buffer); return is; }
Un programma di esempio, che testi la maggior parte delle funzioni della classe su presentata, è il seguente:
// ex10_4_1 #include "stringa.h" void main() { Stringa a, b("Bjarne Stroustrup"), c(b); a = b; cout << a << "\n"; cin >> a; cout << c + a << "\n"; cout << c + " e' il padre del C++" << "\n"; cout << "il C++ e' nato grazie a " + c << "\n"; cout << b - 5 << "\n"; a = Stringa("Philip"); a += " Zimmermann"; a += Stringa(" e' il padre del PGP (pretty good privacy)"); a -= 22; cout << a << "\n"; c = "*-"; c *= 10; cout << c << "\n"; cout << a.maiuscolo() << "\n"; cout << a.minuscolo() << "\n"; b = "sdlavroT"; cout << b.inverti() << "\n"; cout << b.estrai(b.trova("val"), 3) << "\n"; c = "Perdindirindina"; cout << c.conta(Stringa("di")) << "\n"; }
esempio di output:
Bjarne Stroustrup
!!
Bjarne Stroustrup!!
Bjarne Stroustrup e' il padre del C++
il C++ e' nato grazie a Bjarne Stroustrup
Bjarne Strou
Philip Zimmermann e' il padre del PGP
*-*-*-*-*-*-*-*-*-*-
PHILIP ZIMMERMANN E' IL PADRE DEL PGP
philip zimmermann e' il padre del pgp
Torvalds
val
3
Si consiglia di provare ad implementare un maggior numero di funzioni nella classe Stringa
, al fine di prendere confidenza con la gestione delle stringhe e con la progettazione di classi in C++.