Przygotowanie i podstawy
Na początek używamy tylko zmiennych typu string, wejścia z klawiatury, indeksów, pętli i warunków. Dopiero w kolejnej części dodajemy obsługę plików.
Napisy w C++ – string
Do przechowywania tekstu w C++ wykorzystujemy typ
string z biblioteki <string>.
String można traktować jako ciąg znaków, do których dostęp uzyskujemy
podobnie jak do elementów tablicy. W przeciwieństwie do zwykłej tablicy
znaków char, napis typu string może
automatycznie zmieniać swoją długość.
Przykładowa deklaracja napisu:
#include <iostream>
#include <string>
using namespace std;
int main() {
string tekst = "Ala ma kota";
cout << tekst << endl;
}
Dostęp do poszczególnych znaków
Każdy znak w stringu ma swój indeks. Numerowanie zaczyna się od
0, tak jak w tablicach.
string tekst = "kot";
cout << tekst[0] << endl; // k
cout << tekst[1] << endl; // o
cout << tekst[2] << endl; // t
Możemy również wykorzystać pętlę do przejścia przez wszystkie znaki stringu:
string tekst = "kot";
for (int i = 0; i < tekst.length(); i++) {
cout << tekst[i] << endl;
}
Dzięki indeksowaniu można odczytywać, porównywać i zmieniać poszczególne znaki. Należy jednak pamiętać, że indeks musi wskazywać istniejący znak. Dostęp do ostatniego znaku wymaga, aby string nie był pusty. Do napisów typu string w C++ można dołączać inne stringi za pomocą operatora + lub +=, podobnie jak w Pythonie.
Najważniejsze metody i operacje na stringach
| Metoda lub operacja | Zastosowanie | Przykład |
|---|---|---|
length() |
Zwraca długość stringu. | tekst.length() |
size() |
Również zwraca długość stringu. | tekst.size() |
empty() |
Sprawdza, czy string jest pusty. | tekst.empty() |
at(i) |
Zwraca znak o indeksie i i sprawdza, czy indeks jest poprawny. |
tekst.at(0) |
find() |
Wyszukuje znak lub fragment tekstu i zwraca indeks jego pierwszego wystąpienia. | tekst.find("kot") |
substr() |
Pobiera fragment stringu. | tekst.substr(0, 3) |
Przykład wykorzystania kilku metod:
string tekst = "Ala ma kota";
cout << "Dlugosc: " << tekst.length() << endl;
cout << "Pierwszy znak: " << tekst.at(0) << endl;
cout << "Fragment: " << tekst.substr(0, 3) << endl;
cout << "Pozycja slowa: " << tekst.find("kota") << endl;
tekst += "!";
cout << tekst << endl;
find()
Jeżeli wyszukiwany fragment nie występuje w napisie, metoda
find() zwraca string::npos.
Można to wykorzystać do sprawdzenia, czy dany fragment został znaleziony.
if (tekst.find("kot") != string::npos) {
cout << "Znaleziono slowo.";
}
Wczytywanie stringów z klawiatury
Do wczytywania tekstu możemy wykorzystać operator >>
lub funkcję getline(). Różnią się one sposobem traktowania
spacji.
Sposób A – operator >>
string tekst;
cin >> tekst;
Operator >> wczytuje tekst tylko do pierwszego białego
znaku, np. spacji.
Sposób B – funkcja getline()
string tekst;
getline(cin, tekst);
Funkcja getline() wczytuje cały wiersz, łącznie ze spacjami,
aż do końca linii. Jest więc przydatna, gdy użytkownik podaje zdanie
lub dłuższy tekst.
string można indeksować
podobnie jak tablicę, ale nie jest on klasyczną tablicą znaków.
Ponadto w przypadku tekstu zapisanego w UTF-8 polskie litery, takie jak
„ą” lub „ł”, mogą zajmować więcej niż jeden bajt. Metody
length() i indeksowanie nie zawsze odpowiadają więc liczbie
widocznych znaków.
Jak wczytać string?
#include <iostream>
#include <string>
using namespace std;
string tekst;
getline(cin, tekst); // wczytuje całą linię, również spacje
// cin >> tekst; // wczytuje tylko do pierwszej spacji
getline(cin, tekst). Instrukcja cin >> tekst jest odpowiednia, gdy wystarczy jedno słowo.Zadanie 1. Odwracanie napisu – dane z klawiatury
Wczytaj tekst z klawiatury i wypisz znaki w odwrotnej kolejności.
Przykład
Dane wejścioweRóżne sposoby odczytywania znaków z pliku
W C++ można odczytywać plik znak po znaku, linia po linii albo słowo po słowie. Wybór sposobu ma znaczenie: niektóre metody zachowują spacje i nowe linie, a inne je pomijają.
Do odczytywania danych z plików tekstowych wykorzystujemy klasę ifstream z biblioteki <fstream>.
Przykłady poniżej zakładają, że plik tekst.txt został już otwarty do odczytu:
#include <fstream>
ifstream wejscie("tekst.txt");
Sposób 1. wejscie.get(znak) — każdy znak, również spacje
Metoda get(znak) odczytuje jeden znak i zapisuje go w zmiennej typu char. Odczytuje także spacje, tabulatory oraz znaki nowej linii.
char znak;
while (wejscie.get(znak)) {
cout << znak;
}
Kiedy używać? Przy odwracaniu całej zawartości pliku albo liczeniu wystąpień wybranego znaku, także gdy tym znakiem jest spacja.
Sposób 2. wejscie >> znak — odczyt znaków z pominięciem białych znaków
Operator >> pomija białe znaki, czyli spacje, tabulatory i znaki nowej linii. Dla tekstu Ala ma kota kolejne odczytane znaki to A, l, a, m, a, k i tak dalej — bez spacji.
char znak;
while (wejscie >> znak) {
cout << znak;
}
Kiedy używać? Gdy chcesz sprawdzać litery i inne niebiałe znaki, a spacje i podziały linii nie są istotne. Nie używaj tej metody do odtwarzania oryginalnego tekstu.
Sposób 3. getline() i indeksowanie — linia po linii
getline(wejscie, linia) odczytuje jedną linię do zmiennej typu string. Potem możesz użyć indeksu, aby uzyskać każdy znak tej linii.
string linia;
while (getline(wejscie, linia)) {
for (int i = 0; i < linia.size(); i++) {
cout << linia[i];
}
cout << '\n';
}
getline(wejscie, linia)pobiera kolejną linię.linia.size()zwraca długość napisu.linia[i]daje znak o indeksiei, numerowanie zaczyna się od zera.
Uwaga: znak końca linii nie trafia do zmiennej linia. Dlatego przykład wypisuje '\n' po przetworzeniu każdej linii.
Kiedy używać? Gdy tekst ma być analizowany wierszami albo chcesz przetworzyć każdą linię osobno.
Sposób 4. wejscie >> slowo, a potem slowo[i] — słowo po słowie
Operator >> może wczytać całe słowo do zmiennej typu string. Później możesz przejść po wszystkich znakach tego słowa.
string slowo;
while (wejscie >> slowo) {
for (int i = 0; i < slowo.size(); i++) {
cout << slowo[i] << '\n';
}
}
Spacje i nowe linie rozdzielające słowa są pomijane. Znaki interpunkcyjne, na przykład kropka na końcu kota., pozostają częścią słowa.
Kiedy używać? Przy liczeniu słów, szukaniu najdłuższego słowa i analizowaniu liter należących do poszczególnych wyrazów.
char i są przeznaczone do ćwiczeń na podstawowym alfabecie łacińskim. Polskie znaki zapisane w UTF-8 mogą zajmować kilka bajtów, więc proste operacje znak po znaku nie zawsze odpowiadają pojedynczym widocznym literom.Jak zapisywać dane do pliku?
Do zapisywania danych w plikach tekstowych wykorzystujemy klasę
ofstream z biblioteki <fstream>.
Podstawowe elementy obsługi plików:
| Element | Zastosowanie |
|---|---|
ofstream |
Otwieranie pliku do zapisu |
open() |
Otwieranie pliku |
is_open() |
Sprawdzanie, czy plik został otwarty |
<< |
Zapisywanie tekstu i wartości do pliku |
close() |
Zamykanie pliku |
Plik zapisujemy podobnie jak wypisujemy tekst na ekran za pomocą
cout. Zamiast cout używamy jednak obiektu
reprezentującego plik.
Przykład zapisu na ekranie:
cout << "To jest przykladowy tekst.";
Zapis tego samego tekstu do pliku:
ofstream plik("wynik.txt");
// ofstream plik; //alternatywna wersja
// plik.open("wynik.txt");
if (!plik.is_open()) {
cout << "Nie mozna otworzyc pliku.";
return 1;
}
plik << "To jest przykladowy tekst.";
plik.close();
Po uruchomieniu programu w odpowiednim katalogu pojawi się plik
wynik.txt zawierający zapisany tekst.
Zapisywanie tekstu znak po znaku Operator << pozwala zapisać cały napis za jednym razem. Możemy również zapisywać jego kolejne znaki w pętli. Przykład:
string tekst = "Ala ma kota.";
ofstream plik("wynik.txt");
for (int i = 0; i < tekst.length(); i++) {
plik.put(tekst[i]);
}
plik.close();
Metoda put() zapisuje pojedynczy znak do pliku.
break
Instrukcja break natychmiast przerywa wykonywanie
najbliższej pętli for lub while.
Program przechodzi wtedy do instrukcji znajdującej się za pętlą.
Przykład – odczyt pliku do pierwszego znaku końca linii:
char znak;
while (plik.get(znak)) {
if (znak == '\n') {
break;
}
cout << znak;
}
Program odczytuje i wypisuje znaki aż do napotkania '\n'.
Instrukcja break kończy wtedy pętlę, więc pozostała
część pliku nie jest już odczytywana.
Najważniejsze polecenia i metody
| Element | Do czego służy? | Przykład |
|---|---|---|
string | Przechowuje tekst. | string tekst; |
getline(cin, tekst) | Wczytuje całą linię z klawiatury. | getline(cin, tekst); |
tekst.size() | Zwraca liczbę elementów napisu. | tekst.size() |
tekst[i] | Pobiera znak o indeksie i. | cout << tekst[i]; |
ifstream | Otwiera strumień do odczytu z pliku. | ifstream wejscie("tekst.txt"); |
ofstream | Otwiera strumień do zapisu do pliku. | ofstream raport("statystyki.txt"); |
wejscie.get(znak) | Odczytuje kolejny znak, także spację i nową linię. | while (wejscie.get(znak)) |
wejscie >> znak | Odczytuje znak, pomijając białe znaki. | while (wejscie >> znak) |
getline(wejscie, linia) | Odczytuje całą linię bez separatora końca linii. | while (getline(wejscie, linia)) |
wejscie.get() | Zwraca kolejny znak jako int, a koniec pliku jako EOF. | kod = wejscie.get() |
wejscie.peek() | Sprawdza następny znak bez pobierania go. | wejscie.peek() |
wejscie >> slowo | Odczytuje kolejne słowo oddzielone białymi znakami. | while (wejscie >> slowo) |
is_open() | Sprawdza, czy plik został otwarty. | if (!wejscie.is_open()) |
close() | Zamyka plik. | wejscie.close(); |
ios::app | Otwiera plik do dopisywania na końcu. | ofstream raport("statystyki.txt", ios::app); |
<< | Zapisuje tekst do strumienia lub pliku. | raport << "Liczba slow"; |