Prelucrarea cuvintelor dintr-un text
Cum împarți un text în cuvinte, cu strtok și fără, cum le numeri, le compari și refaci textul din ele.
Ce înseamnă „cuvânt"
Într-un enunț de bac, un cuvânt este de obicei o secvență maximă de litere, despărțită de spații sau de semne de punctuație. Când citești enunțul, stabilește mai întâi care sunt separatorii. Un text cu virgule și puncte se tratează altfel decât unul cu spații simple.
Cu strtok
Când separatorii sunt clari, strtok face toată treaba:
char *p = strtok(s, " ");
while (p != NULL) {
// p este un cuvânt
p = strtok(NULL, " ");
}Cu semne de punctuație, dai toți separatorii deodată:
char *p = strtok(s, " ,.;:!?-");Avantajul e că mai mulți separatori la rând sunt tratați corect, fără cuvinte goale între ei.
Reține că strtok distruge textul. Dacă îți mai trebuie, copiază-l înainte.
Fără strtok, de mână
Uneori ai nevoie de poziția cuvântului sau de mai mult control. Atunci parcurgi textul și găsești singur unde începe fiecare cuvânt:
int n = strlen(s);
int i = 0;
while (i < n) {
while (i < n && !isalpha(s[i])) i++; // sar peste separatori
int inceput = i;
while (i < n && isalpha(s[i])) i++; // parcurg cuvântul
if (i > inceput) {
// cuvântul e între pozițiile inceput și i-1
}
}Tiparul general este acesta: sari peste separatori, apoi parcurgi cuvântul. Testul i > inceput evită cuvintele goale de la sfârșitul textului.
Numărarea cuvintelor
Cel mai simplu e să numeri trecerile de la separator la literă.
int cate = 0;
for (int i = 0; s[i] != '\0'; i++)
if (isalpha(s[i]) && (i == 0 || !isalpha(s[i-1])))
cate++;Condiția spune „aici este literă, iar înainte nu era", adică aici începe un cuvânt. Testul i == 0 tratează cazul în care textul începe direct cu o literă. El trebuie pus primul, ca s[i-1] să nu fie citit pentru i = 0. E din nou evaluarea leneșă a lui &&, care aici împiedică o citire în afara șirului.
Față de „număr spațiile plus unu", metoda are un avantaj: merge corect și când textul are spații multiple sau începe și se termină cu spații.
Cel mai lung cuvânt
char cel_mai_lung[101] = "";
char copie[256];
strcpy(copie, s);
char *p = strtok(copie, " ,.");
while (p != NULL) {
if (strlen(p) > strlen(cel_mai_lung))
strcpy(cel_mai_lung, p);
p = strtok(NULL, " ,.");
}
cout << cel_mai_lung;Șirul vid de la inițializare are lungimea 0, deci primul cuvânt îl înlocuiește sigur. Cu > strict se reține primul dintre cuvintele de lungime maximă, iar cu >=, ultimul.
Cuvinte care se repetă
Fără structurile de date interzise la bac, compari direct, cu strcmp, și păstrezi cuvintele într-o matrice de caractere:
char cuvinte[100][21];
int nr = 0;
char *p = strtok(s, " ");
while (p != NULL) {
bool gasit = false;
for (int i = 0; i < nr; i++)
if (strcmp(cuvinte[i], p) == 0) {
gasit = true;
break;
}
if (!gasit)
strcpy(cuvinte[nr++], p);
p = strtok(NULL, " ");
}
cout << nr << " cuvinte distincte";char cuvinte[100][21] este un tablou de 100 de șiruri, fiecare de cel mult 20 de caractere. Așa arată de obicei un „vector de cuvinte" la bac.
Reconstruirea textului
Când elimini sau modifici cuvinte, construiești rezultatul într-un al doilea șir:
char rez[256] = "";
char *p = strtok(s, " ");
while (p != NULL) {
if (strlen(p) % 2 == 0) { // păstrez cuvintele de lungime pară
if (rez[0] != '\0')
strcat(rez, " ");
strcat(rez, p);
}
p = strtok(NULL, " ");
}
cout << rez;Testul rez[0] != '\0' pune spațiu doar între cuvinte, nu și înaintea primului. E același tipar ca indicatorul „primul" de la descompunerea în factori primi, și îl folosești la orice listă cu separator.
Un exemplu complet
Se citește un text. Să se afișeze cuvintele care încep și se termină cu aceeași literă.
#include <iostream>
#include <cstring>
#include <cctype>
using namespace std;
char s[256];
int main() {
cin.getline(s, 256);
char *p = strtok(s, " ,.!?");
while (p != NULL) {
int n = strlen(p);
if (tolower(p[0]) == tolower(p[n-1]))
cout << p << "\n";
p = strtok(NULL, " ,.!?");
}
return 0;
}Aplici tolower pe ambele capete, ca să meargă comparația și la un cuvânt scris cu majusculă la început.
De reținut
- Înainte de orice, stabilește din enunț care sunt separatorii.
strtokeste calea cea mai scurtă, dar distruge textul. Copiază-l dacă îți mai trebuie.- De mână: sari peste separatori, apoi parcurgi cuvântul.
- Numărul de cuvinte = numărul de treceri de la neliteră la literă.
- Compară cuvinte cu
strcmp, niciodată cu==. - La reconstruire, pune separatorul între cuvinte, nu înaintea primului.