I. Các thao tác xử lý chuỗi kí tự
1. Phép so sánh
Như đã đề cập trong phần 9, máy tính sử dụng một bảng chữ cái gồm 256 ký tự, được đánh số từ 0 đến 255. Mỗi ký tự được mã hóa bằng một chuỗi bit nhị phân, được gọi là bảng mã ASCII. Quá trình so sánh hai chuỗi ký tự "X" và "Y" trong ngôn ngữ C++ diễn ra như sau:
Các ký tự trong hai chuỗi được đánh số từ 0. Ta tìm vị trí đầu tiên "i" sao cho ký tự "Xi" khác "Yi". Nếu "Xi" đứng sau "Yi" trong bảng mã ASCII, thì chuỗi "X" được coi là lớn hơn chuỗi "Y". Ngược lại, nếu "Yi" đứng sau "Xi", thì chuỗi "Y" được coi là lớn hơn chuỗi "X".
Trong trường hợp không tìm được vị trí "i" thỏa mãn điều kiện trên, chuỗi dài hơn sẽ được coi là lớn hơn.
Nếu cả hai trường hợp trên không xảy ra, ta kết luận rằng chuỗi "X" bằng chuỗi "Y".
Trong ngôn ngữ C++, ta có thể sử dụng các toán tử >, <, <=, >=, ==, != để so sánh trực tiếp hai ký tự hoặc hai chuỗi, với quy tắc đã nêu trên. Điều này là do hệ thống đã cung cấp các toán tử so sánh tương ứng cho kiểu dữ liệu chuỗi.
Ví dụ 1: Chương trình dưới đây sẽ so sánh hai xâu kí tự và đưa ra xâu lớn hơn
Kết quả chạy chương trình sẽ là:
Chuỗi "Tôi đi học" nhỏ hơn chuỗi "Tôi đi ngủ" vì ký tự "n" có giá trị lớn hơn ký tự "h" trong bảng mã ASCII. Điều thú vị trong việc so sánh chuỗi là mặc dù số 100 lớn hơn số 90, nhưng chuỗi "100" sẽ nhỏ hơn chuỗi "90" vì ký tự "1" đứng trước ký tự "9" trong bảng mã ASCII. Do đó, khi so sánh các số được biểu diễn dưới dạng chuỗi, chúng ta cần chú ý đến điều này (vấn đề này sẽ được đề cập trong chủ đề Xử lý số nguyên lớn trong lập trình thi đấu).
Ví dụ 2: In ra các kí tự chữ cái latin in thường trên một dòng (không có dấu cách):
Kết quả chạy chương trình:
2. Phép nối chuỗi
Khác với phép cộng ở kiểu số, toán tử +
khi được kết hợp với hai chuỗi có ý nghĩa là nối hai chuỗi đó với nhau. Ví dụ dưới đây có thể làm rõ:
Kết quả chạy chương trình sẽ là:
Lưu ý:
- Một đặc điểm của phép cộng chuỗi là chuỗi đứng sau toán tử + sẽ được nối vào phía sau của chuỗi đứng trước toán tử +. Ví dụ, nếu ta viết cout << s2 + s1; trong chương trình, kết quả sẽ là "tôi đi học.Ngày mai" thay vì "Ngày mai tôi đi học".
- Phép nối chuỗi thực chất là tạo ra một bản sao của chuỗi ban đầu, sau đó nối bản sao đó với chuỗi cần nối và gán trở lại cho chuỗi ban đầu. Do đó, phép nối bằng toán tử + có thời gian chạy khá lâu trong các trường hợp chuỗi dài. Vì vậy, cần lưu ý khi sử dụng phép nối chuỗi bằng toán tử +, đặc biệt là đối với các chuỗi có độ dài lớn.
3. Lấy số hiệu trong bảng mã ASCII của một kí tự
Bằng kĩ thuật ép kiểu, ta có thể xác định được số thứ tự trong bảng mã ASCII của một kí tự c bất kỳ, với c là một biến kí tự hoặc hằng kí tự. Cú pháp như sau:
Nếu "c" là một hằng ký tự, ta cần đặt nó trong cặp dấu '', còn nếu "c" là một biến ký tự thì không cần. Ví dụ, để biết số thứ tự của ký tự "a", ta sử dụng câu lệnh (int)('a') để trả về kết quả 97. Tương tự, để biết số thứ tự của biến ký tự "c", ta chỉ cần sử dụng (int)(c). Số hiệu của ký tự phải được sử dụng trong các câu lệnh, không được sử dụng đơn lẻ.
Tương tự, ta có thể xác định ký tự ứng với số hiệu "x" trong bảng mã ASCII bằng cách ép kiểu "char" ngược lại:
Câu lệnh cout << (char)(48); sẽ trả về kết quả là ký tự chữ số 0.
Thực tế, có rất nhiều bài tập ứng dụng liên quan đến việc sử dụng số hiệu ký tự này. Ví dụ, chúng ta có thể sử dụng nó để chuyển đổi từ ký tự số sang dạng số đếm, hoặc để chuyển đổi chữ in hoa thành chữ thường và ngược lại. Tôi khuyến khích bạn đọc tham gia vào phần bài tập của chương này để luyện tập thêm!
5. Các hàm xử lý chuỗi có sẵn trong thư viện của C++
Giả sử chúng ta khai báo một chuỗi ký tự "s" bằng cú pháp: string s;. Bảng dưới đây liệt kê những phương thức xử lý dữ liệu thường được sử dụng và được hỗ trợ sẵn trong lớp <string> dành cho chuỗi "s":
Thư viện <string>
cũng cung cấp các hàm liên quan tới chuyển đổi giữa chuỗi - số ở bảng dưới đây:
Ngoài ra còn rất nhiều phương thức khác được xây dựng sẵn để hỗ trợ người dùng.
6. Xóa các kí tự trong chuỗi:
Khi ta cần xóa một kí tự hoặc một chuỗi con trong chuỗi ban đầu, ta có thể sử dụng phương thức erase() của lớp <string>. Tuy nhiên, khi thực hiện xóa các kí tự trong chuỗi, sẽ có tình huống các kí tự phía sau đoạn bị xóa sẽ bị dịch lên và nối liền với đoạn trước đó, dẫn đến việc số thứ tự của các kí tự trong chuỗi sẽ bị đánh lại. Nếu không cẩn thận trong xử lý, có thể dẫn đến kết quả không chính xác. Chúng ta hãy xem ví dụ sau để xóa các khoảng trắng trong một chuỗi và hiển thị chuỗi sau khi xóa:
Nếu chạy đoạn chương trình trên với s bằng ab c css e ad
, kết quả trả về sẽ như sau:
Chúng ta nhận thấy rằng kết quả hoàn toàn sai. Điều này có nguyên nhân từ việc các ký tự bị đánh số lại và chiều dài chuỗi thay đổi mỗi khi có sự xóa, dẫn đến việc các dấu cách di chuyển theo. Để khắc phục vấn đề này, chúng ta có thể xóa các ký tự hoặc chuỗi con trong một chuỗi từ phải sang trái. Đồng thời, chúng ta cần đảm bảo rằng phần chuỗi phía sau đoạn bị xóa sẽ không còn cần thiết trong quá trình xóa.
Với đoạn code mới này, kết quả sẽ trả ra hoàn toàn chính xác:
II. Chuỗi kí tự theo phong cách ngôn ngữ C (đọc thêm)
Bởi vì C++ dựa trên nền tảng của ngôn ngữ C, nó cũng hỗ trợ xử lý chuỗi ký tự theo phong cách của ngôn ngữ C. Trong C, chuỗi ký tự được biểu diễn dưới dạng một mảng chứa các ký tự. Cú pháp để khai báo chuỗi theo phong cách C như sau:
Các ký tự trong chuỗi kiểu C vẫn được đánh số từ 0. Vì chuỗi là một mảng, nên cách sử dụng của nó cũng tương tự như mảng thông thường. Ví dụ, để khai báo một chuỗi "Hello" theo phong cách C, ta có thể viết như sau: