Bỏ qua

Banner Xử Lý String C++

Buổi 28: Xử Lý Xâu Ký Tự (String)

I. Lý Thuyết

Trong bài trước, ta đã làm quen với việc nhập/xuất và truy xuất các ký tự trong xâu (string). Bài học này sẽ tập trung vào các kỹ thuật Xử lý xâu (String Manipulation) thường gặp nhất: Đếm ký tự, chuyển đổi Hoa/Thường, và Chuẩn hóa chuỗi.


1. Kỹ Thuật Đếm Ký Tự Đặc Biệt

Để đếm một loại ký tự nào đó (ví dụ: đếm chữ 'a', đếm khoảng trắng, đếm chữ số), ta dùng vòng lặp duyệt mảng kết hợp với câu lệnh if.

Ví dụ đếm khoảng trắng (Space):

int count = 0;
for (int i = 0; i < s.length(); i++) {
    if (s[i] == ' ') { // ' ' la ky tu khoang trang (nhay don)
        count++;
    }
}

Ví dụ đếm chữ số (từ '0' đến '9'): Lưu ý: Không viết s[i] == 0 (đây là số nguyên), mà phải viết s[i] >= '0' && s[i] <= '9' (So sánh trong bảng mã ASCII).

if (s[i] >= '0' && s[i] <= '9') {
    // day la ky tu so
}

2. Chuyển Đổi Hoa / Thường

Trong C++, mỗi ký tự có một mã số (Mã ASCII). Ví dụ 'A' có mã là 65, 'a' có mã là 97. Thay vì nhớ mã số phức tạp, ta sử dụng thư viện <cctype> (C Character Types) được hỗ trợ sẵn.

  • toupper(c): Chuyển ký tự c thành CHỮ HOA.
  • tolower(c): Chuyển ký tự c thành chữ thường.
  • Lưu ý quan trọng: Hàm này chỉ trả về kết quả mới chứ không làm thay đổi biến gốc. Phải gán lại: s[i] = toupper(s[i]);
#include <iostream>
#include <string>
#include <cctype> // Thu vien xu ly ky tu
using namespace std;

int main() {
    string s = "aPple";
    s[0] = toupper(s[0]); // Chuyen 'a' thanh 'A'
    s[1] = tolower(s[1]); // Chuyen 'P' thanh 'p'

    cout << s; // In ra: Apple
    return 0;
}

3. Chuẩn Hóa Chuỗi Cơ Bản

Bài toán "Chuẩn hóa tên" là bài toán kinh điển nhất trong xử lý String. Một cái tên đẹp phải thỏa mãn:

  1. Không có khoảng trắng thừa ở ĐẦU và CUỐI xâu.
  2. Không có khoảng trắng thừa Ở GIỮA các từ.
  3. Chữ cái đầu tiên của mỗi từ phải Viết Hoa, các chữ còn lại viết thường.

Kỹ thuật xóa ký tự thừa: Trong thư viện <string>, ta có hàm s.erase(vị_trí, số_lượng).

  • Xóa 1 ký tự tại vị trí i: s.erase(i, 1);
  • Vì thao tác xóa sẽ làm mảng bị thụt lại (Dịch trái), nên ta phải dùng i-- để lùi lại kiểm tra giống hệt bài mảng 1 chiều.

II. Bài Tập Thực Hành Tại Lớp

Bài 1: Đếm Nguyên Âm

Đề bài: Nhập vào một xâu ký tự (viết thường). Đếm xem có bao nhiêu Nguyên Âm trong xâu đó. Các nguyên âm trong tiếng Anh bao gồm: a, e, i, o, u (Mẹo nhớ: U-E-O-A-I).

Gợi ý code
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cout << "Nhap xau: ";
    getline(cin, s);

    int count = 0;
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == 'a' || s[i] == 'e' || s[i] == 'i' || s[i] == 'o' || s[i] == 'u') {
            count++;
        }
    }

    cout << "So luong nguyen am: " << count << endl;
    return 0;
}

Bài 2: Chuyển Toàn Bộ Chuỗi Thành Chữ Hoa

Đề bài: Nhập vào một xâu bất kỳ. Hãy chuyển TẤT CẢ các chữ cái trong xâu thành Chữ In Hoa, sau đó in chuỗi mới ra màn hình.

Gợi ý code
#include <iostream>
#include <string>
#include <cctype> // Bat buoc goi thu vien nay de dung toupper
using namespace std;

int main() {
    string s;
    cout << "Nhap xau: ";
    getline(cin, s);

    for (int i = 0; i < s.length(); i++) {
        s[i] = toupper(s[i]);
    }

    cout << "Chuoi in hoa: " << s << endl;
    return 0;
}

III. Bài Tập Về Nhà

Bài 1: Đếm Số Từ Trong Chuỗi

Đề bài: Nhập vào một xâu \(S\) gồm các từ cách nhau bởi DẤY CÁCH (Khoảng trắng). Giả sử xâu đã được nhập đúng chuẩn (Không có khoảng trắng thừa ở đầu/cuối, và giữa các từ chỉ có đúng 1 khoảng trắng). Hãy in ra số lượng TỪ có trong xâu đó. (Gợi ý: Số từ = Số lượng khoảng trắng + 1).

Output mẫu
Nhap xau: Hom nay troi rat dep
So tu trong xau la: 5

Bài 2: Xóa Khoảng Trắng Thừa Ở Đầu Và Cuối

Đề bài: Nhập vào một xâu có chứa nhiều khoảng trắng thừa ở ĐẦU và CUỐI xâu. Hãy dùng hàm s.erase() để xóa chúng. In ra xâu kết quả (được bọc trong cặp dấu ngoặc vuông [ ] để chứng minh đã xóa sạch).

*(Gợi ý:

  • Xóa đầu: Dùng vòng lặp while(s[0] == ' ') s.erase(0, 1);
  • Xóa cuối: Dùng vòng lặp while(s[s.length() - 1] == ' ') s.erase(s.length() - 1, 1);)*
Output mẫu
Nhap xau: "    Lap Trinh C++      "
Xau sau khi xoa: [Lap Trinh C++]

Bài 3: Sửa Tên Chuẩn Viết Hoa (Khó)

Đề bài: Nhập vào một cái tên (Giả sử không có khoảng trắng thừa). Nhưng người dùng lại nhập hoa/thường lẫn lộn (VD: nGuyen vaN a). Hãy chuẩn hóa: Chữ cái đầu của mỗi từ phải là Chữ Hoa, các chữ cái còn lại trong từ phải là chữ thường \(\to\) Nguyen Van A.

*(Gợi ý:

  • Đầu tiên, chuyển TẤT CẢ về chữ thường tolower().
  • Chữ cái vị trí s[0] luôn luôn viết hoa toupper().
  • Chạy vòng lặp từ 1 đến hết. Nếu phát hiện s[i] == ' ' (khoảng trắng), thì chữ cái ngay đằng sau nó là s[i+1] bắt buộc phải viết hoa).*
Output mẫu
Nhap ten: tRan Van bInH
Ten chuan hoa: Tran Van Binh

Bài 4: Kiểm Tra Mật Khẩu Mạnh

Đề bài: Nhập vào 1 xâu là Mật Khẩu. Một mật khẩu mạnh phải thỏa mãn ĐỒNG THỜI 3 điều kiện:

  1. Chiều dài phải từ 8 ký tự trở lên.
  2. Có ít nhất 1 chữ số.
  3. Có ít nhất 1 chữ cái in hoa. In ra "Manh" nếu thỏa mãn cả 3, ngược lại in "Yeu".
Output mẫu
Nhap mat khau: DucVan123
Manh

Nhap mat khau: ducvan123
Yeu (Vi khong co chu hoa)

IV. Ghi Chú Quan Trọng

So Sánh Mã ASCII

Mỗi ký tự đều được máy tính hiểu như một con số nguyên. Bảng mã ASCII quy định:

  • 'A' = 65, 'B' = 66 ... 'Z' = 90
  • 'a' = 97, 'b' = 98 ... 'z' = 122
  • '0' = 48, '1' = 49 ... '9' = 57

Khoảng cách giữa CHỮ HOA và CHỮ THƯỜNG tương ứng của nó luôn luôn là 32. Do đó, ngoài hàm toupper(), ta có thể chuyển s[i] đang là chữ thường thành hoa bằng phép toán: s[i] = s[i] - 32; (Vì 97 - 32 = 65). Dĩ nhiên, dùng thư viện <cctype> vẫn an toàn và chuyên nghiệp hơn!


V. Ôn Tập Trắc Nghiệm

Kiểm tra kỹ năng Xử lý Chuỗi:

Làm bài trắc nghiệm Buổi 28