Compararea șirurilor de caractere
În limbajul C++ pot fi aplicate operații de comparare pentru șiruri.
= < <= == != <=> ( Aceste operații compară doi obiecti de tip string sau un obiect string cu un literal de șir de caractere. În toate aceste operații, operanzii sunt comparați caracter cu caracter, până când este găsită o pereche de caractere diferite sau până când se ajunge la sfârșitul unuia sau ambilor operanzi.)
Când o pereche de caractere este diferită, compararea codurilor numerice ale caracterelor determină care șir este „mai mic” sau „mai mare”. Dacă nu sunt găsite caractere diferite, dar șirurile au lungimi diferite, șirul mai scurt este considerat „mai mic”. Două șiruri sunt egale dacă au același număr de caractere și toate codurile caracterelor corespunzătoare sunt egale.
Această metodă de comparare se numește și comparare lexicografică. Trebuie remarcat faptul că, întrucât se compară codurile numerice ale caracterelor, rezultatul depinde și de majuscule și minuscule.
De exemplu, operatorul == returnează true dacă toate caracterele ambelor șiruri sunt egale:
std::string s1 {"hello"};
bool result {s1 == "Hello"}; // false - șirurile diferă ca registru
result = s1 == "hello"; // true
Pentru că „hello” și „Hello” diferă prin registrul primei litere, și codul caracterului este diferit, deci șirurile nu sunt egale.
Un alt exemplu - operatorul > (mai mare):
std::string s1 {"helm"};
std::string s2 {"hello"};
bool result {s1 > s2}; // true
În acest caz, condiția s1 > s2 este adevărată, adică s1 este mai mare decât s2, deoarece primele trei caractere („hel”) sunt identice, dar al patrulea caracter din s1 („m”) urmează în alfabet după caracterul corespondent din s2 („l”), deci „m” este mai mare decât „l” (chiar dacă „hello” are mai multe caractere decât „helm”).
Să luăm un mic program. De exemplu, avem un tablou de nume și vrem să le sortăm în ordine alfabetică:
#include <iostream>
#include <string>
int main() {
std::string people[] {"Tom", "Alice", "Sam", "Bob", "Kate"};
// sortăm în ordine crescătoare
bool sorted {};
do
{
sorted = true; // rămâne true dacă șirurile sunt sortate
std::string temp; // variabilă pentru schimb de valori
for (unsigned i {1}; i < std::size(people); i++)
{
// dacă șirul anterior este mai mare decât cel următor
if (people[i-1] > people[i])
{
// facem schimb de valori
temp = people[i];
people[i] = people[i-1];
people[i-1] = temp;
sorted = false;
}
}
} while (!sorted);
// afișăm șirurile la consolă
for (const auto person: people)
{
std::cout << person << std::endl;
}
}
Aici este utilizată o sortare tip bubble sort, nu foarte rapidă, dar clară, care compară șirul anterior cu cel următor. Dacă primul este „mai mare” decât al doilea, valorile sunt schimbate printr-o variabilă intermediară temp. Pentru optimizare, a fost adăugată variabila sorted. De fiecare dată când se face un schimb, această variabilă este setată pe false, ceea ce înseamnă că bucla do-while trebuie reluată.
Afișarea în consolă:
Alice
Bob
Kate
Sam
Tom
Funcția compare()
Pentru compararea șirurilor se poate folosi și funcția compare(). Se transmite un alt șir care se compară cu șirul curent. Funcția compare() returnează:
- 0 dacă șirurile sunt egale
- un număr pozitiv dacă șirul curent este mai mare
- un număr negativ dacă șirul curent este mai mic
Exemplu:
std::string tom {"Tom"};
std::string person{"Tom"};
int result = tom.compare(person);
std::cout << result << std::endl; // 0 - șiruri egale
Alt exemplu:
std::string tom {"Tom"};
std::string bob{"Bob"};
std::string sam {"Sam"};
int result = sam.compare(bob); // 1 - primul șir (sam) > al doilea (bob)
std::cout << result << std::endl; // 1
result = sam.compare(tom); // -1 - primul șir (sam) < al doilea (tom)
std::cout << result << std::endl; // -1
În acest caz, „Sam” este mai mare decât „Bob”, deci funcția returnează 1. În comparația cu „Tom”, „Sam” este mai mic, deci rezultatul este -1.
Versiuni ale funcției compare()
Una dintre formele funcției acceptă trei parametri:
int compare(size_t _Off, size_t _Nx, const std::string &_Right) const
- Primul parametru: indexul primului caracter din șirul curent de la care începe subșirul
- Al doilea: lungimea subșirului
- Al treilea: șirul cu care se compară subșirul
Unde putem folosi asta? De exemplu, vrem să găsim indexul de la care un șir apare în altul:
#include <iostream>
#include <string>
int main() {
std::string text {"Hello world!"};
std::string word {"world"};
for (unsigned i{}; i < text.length() - word.length() + 1; i++)
{
if (text.compare(i, word.length(), word) == 0)
{
std::cout << "text contains " << word << " at index " << i << std::endl;
}
}
}
Aici încercăm să găsim șirul word („world”) în șirul text („Hello world!”). În buclă trecem prin caracterele șirului text, până la indexul text.length() - word.length() + 1.
Comparația se face cu:
if (text.compare(i, word.length(), word) == 0)
Adică din text comparăm un subșir care începe de la indexul i și are word.length() caractere, cu șirul word. Dacă este găsită egalitate, se afișează indexul i.
Ieșire:
text contains world at index 6
Compararea a două subșiruri
#include <iostream>
#include <string>
int main() {
std::string text {"Hello world!"};
std::string word {"world"};
unsigned size {2}; // număr de caractere din al doilea șir
for (unsigned i{}; i < text.length() - size + 1; i++)
{
if (text.compare(i, size, word, 1, size) == 0)
{
std::cout << "text contains substring at index " << i << std::endl;
}
}
}
Aici algoritmul este același. Doar că acum comparăm un subșir din word de lungime size, începând de la indexul 1 (adică subșirul „or”), cu un subșir din text.
Ieșire:
text contains substring at index 7