ΣΥΜΒΟΛΟΣΕΙΡΕΣ Γεώργιος Παπαϊωάννου (2013-14) gepap@aueb.gr
Περιγραφή: Ο τύπος string Μετατροπή από και προς τον τύπο string Βασικές μέθοδοι Χρήση Ελληνικών Συναρτήσεις C εκτύπωσης και ανάγνωσης Τελευταία ενημέρωση: Ιούνιος 2013 Εισαγωγή - 2
Είδαμε ότι τα null-terminated strings (πίνακες χαρακτήρων) μπορούν να χρησιμοποιηθούν ως strings Στη C++ υπάρχει ειδική κλάση, η string που ενσωματώνει μια αντικειμενοστρεφή υλοποίηση των συμβολοσειρών και παρέχει υποστήριξη για σύνθετες αναπαραστάσεις χαρακτήρων, όπως Unicode, wide characters κλπ. Σημείωση: Εξακολουθούμε να δουλεύουμε με πίνακες χαρακτήρων όταν: Θέλουμε συμβατότητα με C (γίνεται και μετατροπή μεταξύ των 2 τύπων Επιθυμούμε μεγαλύτερη ταχύτητα (απλούστερη αναπαράσταση) 3
#include <string> #include <iostream> using namespace std; // Εδώ δηλώνεται το string // Εδώ ανήκει το string (std::string) int main() { string s1, s2; // Δε χρειάζεται να καθορίσουμε τα μεγέθη. cin >> s1; // Ο χώρος του s1 προσαρμόζεται αυτόματα. s2 = "copy of " + s1; // Πρόσθεση συμβολοσειρών. Μετατροπή // του πίνακα χαρακτήρων σε string. s1 = "new string"; // Νέα τιμή του s1. cout << s1 << endl << s2 << endl; } Πληκτρολογώ "test". Τυπώνει: new string copy of test 4
Η κλάση string είναι μέρος της βασικής βιβλιοθήκης «standard template library» (STL) η οποία είναι σπασμένη σε διάφορα αρχεία (π.χ. iostream, string κλπ) Η βιβλιοθήκη αυτή εντάσσει όλες τις κλάσεις της, τους τύπους της και τις συναρτήσεις της σε έναν κοινό χώρο ονομάτων (namespace), τον std Για να δηλώσω ένα string κανονικά ενσωματώνω και το namespace στο όνομα της κλάσης: std::string Αν δηλώσω ότι «χρησιμοποιώ» αυτό το namespace, μπορώ να το παραλείψω από τη δήλωση: using namespace std; string var = my string ; 5
Από πίνακα χαρακτήρων σε string: char buffer[20] = try me ; std::string str = buffer; Από string σε πίνακα χαρακτήρων: str.c_str(); Πρόσβαση στον εσωτερικό buffer (χαρακτήρων): str.data(); // Δεν είναι αντίγραφο και // δε μπορούμε να το αλλάξουμε (const) 6
Μέγεθος: string.size() και string.length() (ισοδύναμα) Άδεια συμβολοσειρά: string.empty() Ανατρέξτε στον οδηγό αναφοράς για τον πλήρη κατάλογο των μεθόδων του string: http://www.cplusplus.com/reference/string/string/ 7
Σύνθεση συμβολοσειρών: string str1 = try me ; string str2 = now ; string str3 = str1 + str2; str1.append(str2); srt1 += again ; Πρόσβαση σε χαρακτήρες: cout << str3[2] << endl; str3[4] = 'i'; str3[5] = 't'; cout << str3 << endl; // str3: try me now // str1: try me now // (append) try me now again // διάβασμα του 3 ου χαρ.: y // αντικατάσταση του 5 ου χαρ. // αντικατάσταση του 6 ου χαρ. // try it now 8
Σύγκριση συμβολοσειρών: string str1 = Android ; string str2 = Androids ; bool _2gt1 = str1 < str2; // _2gt1 == true str1 = Android4.2 ; str2 = Android3.2 ; _2gt1 = str1 < str2; str1 = Andro ; str2 = Andras ; _2gt1 = str1 < str2; // _2gt1 == false Ο έλεγχος γίνεται λεξικογραφικά. Το αποτέλεσμα ισοδυναμεί με τη σύγκριση των πρώτων από αριστερά ανόμοιων χαρακτήρων // _2gt1 == false 9
Εύρεση sub-string: 2 16 string str1 = "I am a healthy camel"; string str2 = "am"; size_t pos = str1.find(str2); // pos == 2 pos = str1.find(str2, pos+1); // pos == 16 10
string to_string (int val); string to_string (long val); string to_string (long long val); string to_string (unsigned val); string to_string (unsigned long val); string to_string (unsigned long long val); string to_string (float val); string to_string (double val); string to_string (long double val); 11
int stoi (const string& str, size_t* idx = 0, int base = 10); long stol (const string& str, size_t* idx = 0, int base = 10); unsigned long stoul (const string& str, size_t* idx = 0, int base = 10); long long stoll (const string& str, size_t* idx = 0, int base = 10); unsigned long long stoull (const string& str, size_t* idx = 0, int base = 10); float stof (const string& str, size_t* idx = 0); double stod (const string& str, size_t* idx = 0); long double stold (const string& str, size_t* idx = 0); 12
Για να υποστηρίξουμε Ελληνικά σε οποιαδήποτε γλώσσα προγραμματισμού, έχουμε τις ακόλουθες επιλογές, ανάλογα και με το λειτουργικό σύστημα: «Ελληνική» κωδικοποίηση του (7-bit) ASCII, όπως για παράδειγμα η ISO8859-7 Χρήση Unicode κωδικοποίησης (8- και 16-bit): UTF-8, UTF-16 Στο Linux, υποστηρίζεται UTF-8 εγγενώς Χρήση wide characters (wchar_t). Στα Windows έχουμε 16- bit wide characters (UTF-16) ενώ στο Linux έχουμε 32-bit «μεγάλους» χαρακτήρες 13
Αν επιχειρήσουμε να τυπώσουμε Ελληνικό κείμενο απευθείας, θα τυπωθεί πιθανότατα σε λάθος κωδικοποίηση (χρησιμοποιείται η default κωδικοποίηση της C++ C ) Λύση 1: Αλλάζουμε την κωδικοποίηση σε Ελληνικό locale (με την προϋπόθεση ότι το System Locale είναι Ελληνικό!): string str2 = "Ελληνικά"; setlocale(lc_all,"greek"); cout << str2; 14
Λύση 2: Χρησιμοποιούμε μεγάλους χαρακτήρες (UTF16). Για τους μεγάλους χαρακτήρες (wchar_t αντί για char), υπάρχουν οι αντίστοιχες w (wide) δηλώσεις: wstring αντί για string wcout αντί για cout κλπ Τα σταθερά strings δηλώνονται λίγο διαφορετικό τρόπο: wstring mystring = L Καλημέρα ; 15
wstring str1 (L"Ελληνικά"); wcout << str1 << endl; _cputws(str1.c_str()); Δεν τυπώνονται σωστά τα Ελληνικά από την κλάση wstring στο output stream Χρήση της C συνάρτησης εξόδου του string: Σωστή κωδικοποίηση Διάβασμα από την κονσόλα: wchar_t buffer [100] = {97}; _cgetws(buffer); _cputws(buffer); wstring str2(buffer); Κατασκευάζουμε έναν πίνακα από wide characters Δηλώνουμε στην πρώτη θέση του πίνακα τον μέγιστο αριθμό χαρακτήρων που επιτρέπεται να διαβάσουμε Χρησιμοποιούμε την αντίστοιχη συνάρτηση εισόδου συμβολοσειρών μεγάλων χαρακτήρων της C 16
Σε όλες τις τυπικές εγκαταστάσεις Linux, χρησιμοποιείται κωδικοποίηση UTF8, οπότε δε χρειάζεται να χρησιμοποιηθεί wide string Εφόσον το αρχείο που έχουμε γράψει τον κώδικα ή το αρχείο από το οποίο διαβάζουμε συμβολοσειρές είναι σε κωδικοποίηση UTF8, τυπώνονται κανονικά οι χαρακτήρες 17
Η κλάση string είναι της C++ (η C δεν είναι αντικειμενοστρεφής) Όμως, η C παρέχει ένα μεγάλο εύρος συναρτήσεων για πίνακες χαρακτήρων Πολύ βασικές συναρτήσεις για μορφοποιημένη είσοδο και έξοδο συμβολοσειρών: printf, sprintf scanf, sscanf 18
Τυπώνει παραμετρικό μορφοποιημένο κείμενο Παίρνει ως είσοδο μια συμβολοσειρά μορφοποίησης και ένα πλήθος παραμέτρων που «κουμπώνουν» σε κατάλληλες θέσεις μέσα σε αυτή Παράδειγμα: int hits = 33; long total = 1000; printf( We scored %d out of %ld points.\nthis is %.2f%%.\n, Τυπώνει: hits, total, 100.f*hits/(float)total ); We scored 33 out of 1000 points. This is 3.30%. 19
Θέση 1 Θέση 2 Θέση 3 printf( We scored %d out of %ld points.\nthis is %.2f%%.\n, hits, total, 100.f*hits/(float)total ); Παράμετρος 1 Παράμετρος 2 Παράμετρος 3 % : δηλώνει ότι ακολουθεί εκτύπωση παραμέτρου %d : εκτυπώνει δεκαδικό αριθμό (decimal) %ld: εκτυπώνει «μεγάλο» δεκαδικό (long decimal) %f: εκτυπώνει float (και double) Πλήρης λίστα: http://www.cplusplus.com/reference/cstdio/printf/ %%: δηλώνει την εμφάνιση του χαρακτήρα % %.2f: Θέλουμε να εμφανίζει 2 δεκαδικά ψηφία 20
Διαβάζει μορφοποιημένα δεδομένα από το ρεύμα εισόδου και περνάει σε μεταβλητές τα ορίσματα που εμφανίζονται στις θέσεις που υποδεικνύουμε Είναι ουσιαστικά η αντίθετη της printf char name[80]; int age; int read = scanf ( name: %s, %d ",name, &age); Αν αποτύχει η ανάγνωση γιατί η συμβολοσειρά εισόδου δεν ταιριάζει στο μορφότυπο που δώσαμε, επιστρέφει αμέσως Η τιμή επιστροφής είναι ο αριθμός των παραμέτρων που διαβάστηκαν ορθά 21
#define STATUS_CODE_PARSING -1 #define STATUS_CODE_OK 0 int parsevec2(float *v, char * text) { if (!text) return STATUS_CODE_PARSING; if ( scanf(text, "\(%f%*[,\t]%f\)", &(v[0]), &(v[1])) < 2 ) return STATUS_CODE_PARSING; else return STATUS_CODE_OK; } 22
scanf(text, "\(%f%*[,\t]%f\)", &(v[0]), &(v[1])) \(, \) : Ειδικοί χαρακτήρες ( ) %f : διάβασμα αριθμού κινητής υποδιαστολής %* : διάβασε και αγνόησε (μην αποθηκεύσεις κάπου) την επόμενη τιμή %[ ] : διάβασε έναν ή περισσότερους από τους χαρακτήρες μέσα στις αγκύλες Ενδεικτικές έγκυρες είσοδοι: (0.04 1.3) (200, 40.45) ( 1.4 50) (-200, 50) 23
Χρήσιμες συναρτήσεις για μορφοποιημένη έξοδο και είσοδο σε/από πίνακες χαρακτήρων Χρήσιμες για εύκολη επεξεργασία συμβολοσειρών (π.χ. parsing γραμμών κειμένου από αρχεία) Έχουν ένα παραπάνω όρισμα (το πρώτο), τον πίνακα χαρακτήρων εισόδου ή εξόδου (δείτε τον οδηγό αναφοράς για περισσότερες πληροφορίες) 24