BÀI GIẢNG: XÂU KÝ TỰ (STRING) TRONG C++
1. Giới thiệu về Xâu ký tự trong C++
Trong C++, để xử lý chuỗi văn bản (tên, văn bản, chuỗi số...), chúng ta có hai cách chính:
- C-style string: Mảng các ký tự kiểu
charkết thúc bằng ký tự null\0(kế thừa từ ngôn ngữ C). std::string(Class String): Kiểu dữ liệu hướng đối tượng thuộc thư viện chuẩn của C++. Đây là cách tiếp cận hiện đại, an toàn và linh hoạt hơn rất nhiều.
Bài giảng này sẽ tập trung toàn bộ vào std::string.
Cú pháp khai báo thư viện:
C++#include <iostream> #include <string> // Thư viện bắt buộc để dùng string using namespace std;
2. Các cách khởi tạo một Xâu ký tự
Có rất nhiều cách để khai báo và khởi tạo một đối tượng string:
string s1; // Khởi tạo xâu rỗng ("")
string s2 = "Hello"; // Khởi tạo với chuỗi literal
string s3("World"); // Khởi tạo giống như gọi constructor
string s4(s2); // Sao chép từ xâu s2 (s4 = "Hello")
string s5(5, 'A'); // Tạo xâu gồm 5 ký tự 'A' -> "AAAAA"
3. Nhập/Xuất Xâu ký tự (Input/Output)
Việc nhập dữ liệu cho xâu ký tự trong C++ cần lưu ý hiện tượng trôi lệnh khi có khoảng trắng.
3.1. Dùng cin (Bị giới hạn bởi khoảng trắng)
cin sẽ dừng đọc khi gặp dấu cách (space), dấu tab hoặc dấu xuống dòng (\n).
string s;
cout << "Nhập xâu: ";
cin >> s; // Nếu nhập "Tin Học", s chỉ nhận được "Tin"
cout << "Xâu vừa nhập: " << s << endl;
3.2. Dùng getline() (Đọc toàn bộ dòng, có cả khoảng trắng)
Để đọc một chuỗi có khoảng trắng, ta dùng hàm getline().
string s;
cout << "Nhập họ và tên: ";
getline(cin, s); // Nhập "Nguyễn Văn A" -> s nhận toàn bộ "Nguyễn Văn A"
cout << "Xin chào: " << s << endl;
⚠️ Lưu ý sửa lỗi trôi lệnh (cin.ignore())
Nếu trước lệnh getline() có một lệnh cin >> (ví dụ nhập số tuổi, số lượng), ký tự xuống dòng \n vẫn còn sót lại trong bộ nhớ đệm. getline() sẽ đọc ký tự \n này và kết thúc ngay lập tức khiến xâu bị rỗng.
- Giải pháp: Dùng
cin.ignore()trướcgetline().
int age;
string name;
cin >> age;
cin.ignore(); // Xóa ký tự '\n' còn sót lại
getline(cin, name);
4. Truy cập ký tự và Duyệt xâu
Mỗi ký tự trong xâu được đánh chỉ số (index) bắt đầu từ 0 đến n-1 (với n là độ dài xâu).
4.1. Truy cập qua chỉ số [] hoặc .at()
s[i]: Nhanh hơn, nhưng không kiểm tra nếu chỉ sốivượt quá phạm vi.s.at(i): An toàn hơn, ném ra ngoại lệ nếuihợp lệ.
4.2. Các cách duyệt xâu phổ biến
- Cách 1: Duyệt bằng chỉ số (Index-based loop)
string s = "Hello";
for (int i = 0; i < s.length(); i++) {
cout << s[i] << " ";
} // Đầu ra: H e l l o
- Cách 2: Duyệt qua từng ký tự (Range-based for loop - C++11)
string s = "C++";
for (char c : s) {
cout << c << "-";
} // Đầu ra: C-+-+-
5. Bảng tổng hợp các Hàm (Methods) thành viên của std::string
Dưới đây là hệ thống toàn bộ các hàm thông dụng được chia theo nhóm chức năng:
5.1. Nhóm hàm kiểm tra kích thước
| Tên hàm | Chức năng | Ví dụ |
|---|---|---|
s.length() hoặc s.size() |
Trả về độ dài (số ký tự) của xâu. | "Hi".length() \(\rightarrow\) 2 |
s.empty() |
Kiểm tra xâu có rỗng không (trả về true/false). |
s.empty() |
s.clear() |
Xóa toàn bộ nội dung xâu, biến xâu thành rỗng. | s.clear(); |
5.2. Nhóm hàm chỉnh sửa xâu (Thêm, Xóa, Chèn, Thay thế)
| Tên hàm | Chức năng | Ví dụ minh họa |
|---|---|---|
s.push_back(ch) |
Thêm ký tự ch vào cuối xâu. |
s = "Abc"; s.push_back('D'); \(\rightarrow\) "AbcD" |
s.pop_back() |
Xóa 1 ký tự ở cuối xâu (C++11). | s = "Abc"; s.pop_back(); \(\rightarrow\) "Ab" |
s.append(str) |
Nối xâu str vào cuối xâu s (tương đương toán tử +=). |
s.append("Def"); |
s.insert(pos, str) |
Chèn xâu str vào vị trí pos. |
"Hlo".insert(1, "el") \(\rightarrow\) "Hello" |
s.erase(pos, len) |
Xóa len ký tự bắt đầu từ vị trí pos. |
"Hello".erase(1, 2) \(\rightarrow\) "Hlo" |
s.replace(pos, len, str) |
Thay thế len ký tự từ vị trí pos bằng xâu str. |
"AxxB".replace(1, 2, "yy") \(\rightarrow\) "AyyB" |
5.3. Nhóm hàm tìm kiếm và cắt xâu
| Tên hàm | Chức năng | Chi tiết |
|---|---|---|
s.substr(pos, len) |
Trích xuất một xâu con từ vị trí pos với độ dài len. |
Nếu bỏ qua len, hàm sẽ cắt đến hết xâu. |
s.find(str) |
Tìm vị trí xuất hiện đầu tiên của xâu str trong s. |
Trả về chỉ số đầu tiên, nếu không thấy trả về string::npos. |
s.rfind(str) |
Tìm vị trí xuất hiện cuối cùng của xâu str. |
Duyệt từ phải qua trái. |
6. Các toán tử (Operators) trên Xâu
std::string hỗ trợ các toán tử trực quan giúp code ngắn gọn hơn:
-
Toán tử
+và+=: Dùng để ghép (nối) xâu.
C++string a = "Tin", b = "Học"; string c = a + " " + b; // c = "Tin Học" -
Toán tử so sánh (
==,!=,<,>,<=,>=): So sánh hai xâu theo thứ tự từ điển (Lexicographical order).
C++string x = "Apple"; string y = "Banana"; if (x < y) cout << "Apple đứng trước Banana trong từ điển";
7. Các hàm bổ trợ quan trọng (Thuộc thư viện <cctype> và <algorithm>)
Để xử lý xâu nâng cao, ta thường kết hợp các hàm ngoài thư viện string.
7.1. Thư viện <cctype> (Xử lý từng ký tự)
toupper(c): Chuyển ký tự thành chữ hoa.tolower(c): Chuyển ký tự thành chữ thường.isalpha(c): Kiểm tra có phải chữ cái không.isdigit(c): Kiểm tra có phải chữ số không.
7.2. Chuyển đổi Xâu \(\leftrightarrow\) Số (C++11)
-
Số sang Xâu:
to_string(value)
C++int n = 123; string s = to_string(n); // s = "123" -
Xâu sang Số:
stoi(s)(sang int),stoll(s)(sang long long),stod(s)(sang double).
C++string s = "45.67"; double d = stod(s); // d = 45.67
7.3. Đảo ngược xâu (Thư viện <algorithm>)
string s = "abcdef";
reverse(s.begin(), s.end()); // s trở thành "fedcba"
8. Ví dụ thực hành tổng hợp
Ví dụ 1: Chuẩn hóa tên (Viết hoa chữ cái đầu, xóa khoảng trắng thừa)
Bài toán kinh điển trong xử lý xâu: Chuyển chuỗi " nGuYễN vĂn a " thành "Nguyễn Văn A". (Để đơn giản, ví dụ dưới đây minh họa với ký tự không dấu).
#include <iostream>
#include <string>
#include <sstream>
#include <cctype>
using namespace std;
int main() {
string input = " lLê hOàNg vŨ ";
stringstream ss(input); // Tách xâu dựa vào khoảng trắng
string word;
string result = "";
while (ss >> word) {
// Chuyển chữ cái đầu thành hoa, các chữ sau thành thường
word[0] = toupper(word[0]);
for (int i = 1; i < word.length(); i++) {
word[i] = tolower(word[i]);
}
result += word + " ";
}
// Xóa dấu cách thừa ở cuối cùng
if (!result.empty()) {
result.pop_back();
}
cout << "Xâu chuẩn hóa: \"" << result << "\"" << endl;
// Kết quả: "Lê Hoàng Vũ"
return 0;
}
Ví dụ 2: Kiểm tra xâu đối xứng (Palindrome)
Xâu đối xứng là xâu đọc từ trái qua phải hay từ phải qua trái đều như nhau (Ví dụ: "radar", "abba").
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
bool isPalindrome(string s) {
string rev = s;
reverse(rev.begin(), rev.end());
return s == rev;
}
int main() {
string s;
cout << "Nhập xâu cần kiểm tra: ";
cin >> s;
if (isPalindrome(s)) {
cout << s << " là xâu đối xứng." << endl;
} else {
cout << s << " không phải là xâu đối xứng." << endl;
}
return 0;
}
9. Câu hỏi củng cố & Bài tập đề xuất
- Phân biệt
s.length()vàsizeof(s). Tại sao không dùngsizeof()chostd::string? - Bài tập 1: Viết chương trình đếm số lượng chữ cái, chữ số và ký tự đặc biệt trong một xâu nhập từ bàn phím.
- Bài tập 2: Viết hàm tìm kiếm và thay thế tất cả các từ "anh" thành từ "em" trong một đoạn văn bản.
Bình luận