Merkkijonot ja merkit¶
Pythonissa merkkijonotietotyyppi (str
) kuuluu muuttumattomien
(immutable) tietotyyppien joukkoon. Tämä tarkoittaa sitä, että
merkkijonotyyppistä arvoa ei voi muuttaa:
def main():
teksti = "abcdefg"
print(teksti[3]) # Tulostuu: d
teksti[3] = "X" # VIRHE!
print(teksti)
main()
Tämä ongelma vältettiin sillä, että aina kun merkkijonon sisältämää tekstiä haluttiin muokata, luotiin uusi merkkijonotyyppinen arvo, johon muutos oli huomioitu, ja nimettiin uusi arvo samalla nimellä kuin alkuperäinen:
def main():
teksti = "abcdefg"
print(teksti[3]) # Tulostuu: d
teksti = teksti[:3] + "X" + teksti[4:]
print(teksti) # Tulostuu: abcXefg
main()
C++:ssa jo olemassa olevaa merkkijonoakin voi muuttaa (paitsi jos se
on const string
-tyyppinen vakio):
#include <iostream>
#include <string> // Huomaa string-kirjasto
using namespace std;
int main() {
string teksti = "abcdefg";
cout << teksti.at(3) << endl; // Tulostuu: d
teksti.at(3) = 'X'; // Huomaa char-tyyppi
cout << teksti << endl; // Tulostuu: abcXefg
}
Sekä Pythonissa että C++:ssa merkkijonon merkkien indeksointi alkaa nollasta.
C++:ssa merkkijonon yksittäiset merkit ovat char
-tyyppisiä, eli
indeksointioperaatio teksti.at(indeksi)
tuottaa aina
char
-tyyppisen arvon, tai jos indeksointioperaatio on sijoituksen
kohteena, sijoitettavan arvon on oltava char
.
Merkkijonoihin kohdistuvat nimetyt operaatiot ovat C++:ssa metodeja kuten Pythonissakin:
#include <iostream>
#include <string>
using namespace std;
int main() {
string teksti = "One string to rule them all...";
cout << teksti.length() << endl;
cout << teksti.substr(4, 14) << endl;
teksti.replace(4, 6, "thing");
cout << teksti << endl;
}
Jotkut merkkijonoja käsittelevät operaatiot tuottavat paluuarvonaan lukuarvoja, esimerkiksi:
teksti.length(); // Merkkien lukumäärä
teksti.find("abc"); // Mistä kohdasta löytyy ensimmäinen "abc"?
Jos näitä merkkijonoihin liittyviä lukuarvoja (merkkien määrä, indeksit)
haluaa tallettaa muuttujaan, sen tyypin on oltava string::size_type
:
#include <iostream>
#include <string>
using namespace std;
int main() {
string nimi = "";
string::size_type apu = 0;
cout << "Syötä nimesi: ";
getline(cin, nimi);
apu = nimi.length();
cout << "Nimessa " << apu << " kirjainta" << endl;
apu = nimi.find("nen");
if ( apu == string::npos ) {
cout << "Nimessa ei kirjainyhdistelmaa \"nen\"." << endl;
} else {
cout << "Yhdistelma \"nen\" loytyi kohdasta " << apu << endl;
}
}
Huomaa, kuinka find
palauttaa arvon string::npos
, jos etsittyä
merkkiyhdistelmää ei löydy.
Hyödyllisiä merkkijono-operaatioita¶
Metodit¶
Metodeja kutsutaan notaatiolla muuttuja.metodi(parametrit)
.
string::size_type length()
Paluuarvo kertoo, kuinka monta merkkiä merkkijonossa on.
string::size_type pituus = 0; pituus = teksti.length();
char at(indeksi)
Palauttaa merkkijonon indeksinnen merkin. Jos
at
-funktion kutsu on sijoituksen kohteena, korvaa indeksinnen merkin.char merkki; merkki = teksti.at(5); teksti.at(2) = 'k'; // Huomaa char-tyyppi
string erase(indeksi)
string erase(indeksi, pituus)
Jos kutsussa on vain yksi parametri, tuhoaa merkkijonosta kaikki merkit kohdasta indeksi alkaen. Jos kutsussa myös parametri pituus, tuhoaa niin monta merkkiä eteenpäin.
teksti.erase(4); teksti.erase(2, 5);
string::size_type find(etsittävä)
string::size_type find(etsittävä, indeksi)
Etsii merkkijonon alusta (tai kohdasta indeksi) alkaen ensimmäisen vastaantulevan etsittava-merkkijonon sijaintikohdan ja palauttaa kyseisen kohdan indeksin. Jos etsittavaa ei löydy, paluuarvo on vakio
string::npos
.string::size_type kohta = 0; kohta = teksti.find("abc", 5); if ( kohta == string::npos ) { // Ei löytynyt "abc":tä indeksistä 5 eteenpäin } else { // "abc" löytyi. }
string::size_type rfind(etsittävä)
string::size_type rfind(etsittävä, indeksi)
Kuten funktio
find
edellä, mutta etsii merkkijonon lopusta alkua kohti.string substr(indeksi)
string substr(indeksi, pituus)
Palauttaa merkkijonon osan. Jos kutsussa on vain yksi parametri, paluuarvo on osamerkkijono kohdasta indeksi merkkijonon loppuun saakka. Jos annetaan myös parametri pituus, palautuu sen ilmoittama määrä merkkejä kohdasta indeksi eteenpäin.
string teksti = "abcdefg"; string tulos; tulos = teksti.substr(3); // "defg" tulos = teksti.substr(4, 2); // "ef"
string insert(indeksi, lisays)
Lisätään kohdan indeksi eteen teksti lisays.
string teksti = "abcd"; teksti.insert(2, "xy"); // "abxycd"
string replace(indeksi, pituus, korvaaja)
Korvataan merkkijonossa merkistä indeksi alkaen pituus merkkiä tekstillä korvaaja.
string teksti = "ABCDEF"; teksti.replace(1, 3, "xy"); // "AxyEF"
Operaattorit¶
teksti1 == teksti2
teksti1 != teksti2
teksti1 < teksti2
teksti1 > teksti2
teksti1 <= teksti2
teksti1 >= teksti2
Vertailuoperaattoreilla voi vertailla merkkijonojen suhdetta toisiinsa. Operaattorit, joissa on mukana pienempi- tai suurempi kuin -operaatio, vertailevat nk. leksikaalijärjestystä, joka on merkkijonojen tapauksessa lähes sama asia kuin aakkosjärjestys.
teksti1 + teksti2
Liimataan (katenoidaan) kaksi merkkijonoa yhdeksi.
string testi1 = "Qt"; string testi2 = "Creator"; string tulos; tulos = testi1 + " " + testi2; // "Qt Creator"
merkkijono += lisays
Liimaa (katenoi) merkkijonon perään merkkijonon tai merkin lisays.
string tulos = "Qt"; tulos += ' '; // "Qt " tulos += "Creator"; // "Qt Creator"
Funktiot¶
getline(virta, rivi)
Luetaan tiedostosta tai näppäimistölä (
cin
) yksi rivi tekstiä ja talletetaan se merkkijonoviiteparametriin rivi.int stoi(teksti)
Muutetaan parametri teksti vastaavaksi kokonaisluvuksi.
string numeerinen_teksti = "123"; int luku; luku = stoi(numeerinen_teksti); // 123
double stod(teksti)
Vastaava kuin
stoi
edellä, mutta muuttaa merkkijonon reaaliluvuksi.string numeerinen_teksti = "123.456"; double luku; luku = stod(numeerinen_teksti); // 123.456
Edellisten stoi
- ja stod
-funktioiden ongelmana on se, että ne
eivät tunnista virheellistä syötettä, jos sen alku näyttää oikean
tyyppiseltä luvulta. Esimerkiksi "123abc"
kelpaa
stoi
-funktiolle ja funktio palauttaa 123. Virhettä ei voi tähän
mennessä opituilla tiedoilla huomata helposti.
Merkit¶
Pythonissa merkkejä (kirjaimia) käsiteltiin kuten yhden merkin mittaisia merkkijonoa.
C++:n merkkityyppi char
on oikeastaan kokonaislukutyyppi.
Tätä tyyppiä oleva muuttuja sisältää ASCII-arvon:
cout << "Syötä jokin merkki: ";
char merkki = ' ';
cin >> merkki;
int merkin_ascii_arvo = static_cast< int >( merkki );
cout << "Merkin " << merkki << " ASCII-arvo on " << merkin_ascii_arvo << endl;
Se, että merkki on oikeastaan kokonaisluku, mahdollistaa esimerkiksi merkkimuuttujille suoritettavat laskutoimitukset:
for( char kirjain = 'a'; kirjain < 'z'; ++kirjain ){
cout << kirjain;
}
cout << endl;
Tämä voi olla hyödyllistä, jos jostain syystä haluat käydä ohjelmassa läpi kaikki kirjaimet aakkosjärjestyksessä.
Kirjasto cctype
¶
C++:ssa voi käyttää kirjastoa cctype
(muista include
), joka
sisältää mm. seuraavat funktiot:
islower(merkki)
tarkastaa, onko kyseessä pieni kirjain (paluuarvobool
)isupper(merkki)
tarkastaa, onko kyseessä iso kirjainisdigit(merkki)
tarkastaa, onko kyseessä numeromerkkitolower(merkki)
muuttaa ison kirjaimen vastaavaksi pieneksi kirjaimeksitoupper(merkki)
muuttaa pienen kirjaimen vastaavaksi isoksi kirjaimeksi.
Lisää cctype
-kirjaston funktioita löydät lukuisista
C++-kirjastoreferensseistä Internetistä.