[Tự học C++] Phần 9: Kiến thức về Xâu kí tự trong C++
7/10/2023 10:26:24 AM
tientran21121 ...
I. Dữ liệu dạng văn bản
1. Bảng kí tự ASCII
ASCII (American Standard Code for Information Interchange) là một bảng mã chuẩn được sử dụng để trao đổi thông tin trong hệ thống máy tính. Bảng mã ASCII gồm 256 kí tự được đánh số từ 0 đến 255. Bảng mã này dựa trên bảng chữ cái Latin và bao gồm các kí tự và mã tương ứng của chúng.
Mỗi kí tự trong bảng mã ASCII được mã hóa bằng các giá trị nhị phân (0-1) và có một giá trị thập phân tương ứng để thao tác dễ dàng. Ví dụ, kí tự 'A' có mã thập phân là 65, kí tự 'z' có mã thập phân là 122, và còn nhiều kí tự khác trong bảng mã ASCII.
Trong lập trình, chúng ta thường làm việc với các kí tự in được trong bảng mã ASCII, chẳng hạn như các chữ cái và chữ số. Các kí tự này có thể được sử dụng để biểu diễn văn bản và thực hiện các thao tác xử lý trong máy tính.
trong lập trình, thông tin có thể được biểu diễn dưới dạng số (dạng số nguyên, số thực, v.v.) và dạng phi số (văn bản, hình ảnh, âm thanh, v.v.). Trong lập trình thi đấu, thông tin dạng văn bản xuất hiện thường xuyên và đóng vai trò quan trọng không kém dạng số. Các ngôn ngữ lập trình cung cấp các kiểu dữ liệu đặc biệt để lưu trữ và xử lý thông tin dạng văn bản.
Có hai loại dữ liệu dạng văn bản phổ biến nhất là kiểu kí tự và kiểu chuỗi kí tự (một chuỗi các kí tự được ghép lại).
Đối với kiểu kí tự, trong ngôn ngữ lập trình C++, ta sử dụng kiểu dữ liệu char để biểu diễn. Mỗi biến kiểu char chứa một kí tự duy nhất, ví dụ như 'A', 'b', '1', v.v.
Đối với chuỗi kí tự, ta có hai cách khác nhau để biểu diễn:
Sử dụng một mảng gồm nhiều phần tử kiểu char. Mỗi phần tử trong mảng đại diện cho một kí tự của chuỗi và kết thúc bằng kí tự null '\0. Ví dụ: char myString[] = {'H', 'e', 'l', 'l', 'o', '\0'}.
Sử dụng lớp chuỗi <string> đã được xây dựng sẵn trong C++. Cách này được ưu chuộng hơn vì hỗ trợ thao tác với chuỗi dễ dàng hơn. Ví dụ: string myString = "Hello".
Việc lựa chọn cách biểu diễn chuỗi dựa vào yêu cầu và sự thuận tiện của từng trường hợp. Tuy nhiên, sử dụng lớp chuỗi <string> thường được khuyến khích trong C++ do nó cung cấp nhiều tính năng tiện ích và hỗ trợ xử lý chuỗi một cách linh hoạt hơn.
II. Lớp <string> trong C++
thư viện chuẩn của C++ cung cấp lớp <string> để hỗ trợ việc lưu trữ và xử lý các chuỗi kí tự. Lớp này có nhiều phương thức và tính năng hữu ích để làm việc với chuỗi kí tự.
Dùng thuật ngữ đơn giản, có thể coi <string> như một kiểu dữ liệu đặc biệt trong C++, nhưng nó được thiết kế để giúp người lập trình xử lý dữ liệu chuỗi một cách dễ dàng và tiện lợi.
1. Khai báo và truy cập các phần tử chuỗi
Để khai báo một chuỗi sử dụng lớp <string>, đầu tiên ta cần khai báo thư viện và không gian tên chứa nó bằng cú pháp:
Sau đó, khai báo một chuỗi bằng cú pháp:
Như thông thường, {Tên_chuỗi} là một định danh do người dùng tự đặt, miễn là không trùng với từ khóa đã được định nghĩa trong ngôn ngữ lập trình. Khi sử dụng lớp <string>, chúng ta không cần khai báo độ dài của chuỗi trước, mà mỗi khi thêm một kí tự vào, độ dài của chuỗi sẽ tự động điều chỉnh để phù hợp với số lượng kí tự.
Khi khai báo một chuỗi, mặc định chuỗi đó sẽ là chuỗi rỗng, tức là không có kí tự nào trong đó.
Các kí tự trong chuỗi được đánh số từ 0. Để truy cập một vị trí cụ thể trong chuỗi (với điều kiện vị trí đó hiện có kí tự hoặc đã được khởi tạo), chúng ta sử dụng cú pháp:
Việc truy cập và thao tác trên các vị trí trong chuỗi tương tự như làm việc với mảng. Sau khi truy cập, mỗi vị trí trong chuỗi có thể được thao tác giống như một kí tự đơn lẻ và có thể kết hợp với các câu lệnh và toán tử khác.
Ví dụ, để gán một biến c bằng kí tự ở vị trí thứ 2 trong chuỗi s, chúng ta có thể sử dụng cú pháp:
2. Cách nhập xuất một chuỗi
2.1. Nhập xuất các biến kiểu <string>
khi nhập và xuất một biến chuỗi kí tự, ta có thể coi chuỗi đó như một biến đơn và sử dụng hai câu lệnh cin và cout để thực hiện nhập và xuất dữ liệu. Cú pháp được sử dụng như sau:
khi sử dụng lệnh cin để nhập chuỗi kí tự, có một lưu ý quan trọng. Khi gặp dấu cách trong quá trình nhập liệu, lệnh cin sẽ dừng và chỉ lưu trữ phần của chuỗi từ đầu cho đến trước dấu cách. Các kí tự sau dấu cách sẽ không được đưa vào chuỗi. Cùng xem ví dụ dưới đây:
Nếu người dùng nhập vào một tên là Vũ Quế Lâm, thì khi chạy chương trình ta sẽ thu được kết quả này:
Do đó, trong trường hợp cần đọc vào một chuỗi có cả dấu cách, ta sẽ sử dụng kết họp hai cú pháp:
Lệnh getline() sẽ thu nhận cả dòng dữ liệu nhập vào, bao gồm cả những dấu cách. Nó sẽ dừng việc đọc lại khi gặp kí tự \n - tức là kí tự xuống dòng:
Vẫn còn nội dung phía dưới, bạn hãy ấn nút để xem tiếp nhé...
Lúc này, với tên nhập vào là Vũ Quế Lâm, chạy chương trình sẽ thu được kết quả chính xác:
2.2. Nhập nhiều chuỗi kí tự hoặc chuyển đổi từ nhập số sang nhập chuỗi bằng getline()
Nếu chúng ta chỉ nhập một chuỗi kí tự duy nhất, thì không có gì đáng chú ý cả. Chỉ cần lựa chọn giữa cin và getline(cin) tùy thuộc vào việc chuỗi nhập vào có dấu cách hay không. Tuy nhiên, khi dữ liệu đầu vào bao gồm nhiều chuỗi kí tự khác nhau hoặc số và chuỗi kết hợp, thì có những điều khác biệt. Thực chất, khi nhập bất kỳ thứ gì từ bàn phím, nó sẽ được lưu vào bộ nhớ đệm, sau đó hàm cin sẽ "đọc" dữ liệu từ bộ nhớ đệm và gán cho biến.
Ví dụ, nếu chúng ta nhập một số là 123 , 123 và nhấn Enter (kí tự xuống dòng), thì 123 123 và kí tự \n sẽ được lưu trong bộ nhớ đệm trước, sau đó hàm cin sẽ "quét qua" dữ liệu trong bộ nhớ đệm và gán nó cho biến phù hợp. Trong trường hợp biến là một biến số, chỉ có các chữ số mới được lưu vào biến, các kí tự như \n sẽ bị bỏ qua. Điều này cho phép chương trình phân tách các số đúng, dù có sử dụng dấu cách hoặc xuống dòng. Tuy nhiên, nếu sau số là một kí tự hoặc chuỗi, nó sẽ đọc cả kí tự \n (vì kí tự \n không bị bỏ qua và vẫn còn trong bộ nhớ đệm), dẫn đến việc đọc sai chuỗi kí tự. Hãy xem ví dụ dưới đây:
Nếu như nhập vào dữ liệu là id=1 và name= Nguyen Van A, thì khi chạy chương trình các bạn sẽ thấy kết quả in ra chỉ có như sau:
Nguyên nhân là khi nhập số 1, chúng ta nhấn Enter hoặc dấu cách. Biến � id chỉ có thể đọc được số 1, còn kí tự dấu cách hoặc xuống dòng vẫn còn trong bộ nhớ đệm. Hàm getline(cin, name) tiếp theo sẽ đọc cả những kí tự đó, dẫn đến hai trường hợp sau:
Nếu kí tự còn lại là dấu cách, thì kí tự đó sẽ được thêm vào đầu chuỗi kí tự name. Nếu kí tự còn lại là dấu xuống dòng, thì hàm getline() sẽ dừng lại ngay lập tức và chuỗi kí tự name sẽ không có giá trị. Tổng hợp lại, dữ liệu của chúng ta sẽ bị sai! Vậy giải pháp là gì? Chúng ta cần xóa bộ nhớ đệm trước khi nhập chuỗi (cho dù nhập một chuỗi hay nhiều chuỗi). Trong ngôn ngữ C++, hàm cin cung cấp phương thức cin.ignore() để làm điều này. Cú pháp như sau:
Phương thức cin.ignore() được sử dụng để xóa n kí tự trong bộ nhớ đệm cho đến khi gặp kí tự c, sau đó luồng nhập dữ liệu sẽ bắt đầu từ kí tự ngay sau kí tự c. Nếu không chỉ định tham số, chương trình sẽ mặc định xóa 1 kí tự trong bộ nhớ đệm. Điều này hữu ích khi chúng ta muốn nhập chuỗi ngay sau một số, thường là sau khi nhập số chúng ta có thói quen dùng một dấu cách hoặc xuống dòng. Do đó, đoạn code trên có thể sửa lại như sau:
Lúc này, kết quả sẽ trở nên chính xác với bộ dữ liệu nhập vào:
2.3. Xuất ra các hằng chuỗi hoặc hằng kí tự
Trong C++, khi cần viết các hằng chuỗi hoặc hằng kí tự, chúng ta có quy tắc như sau:
Khi viết một kí tự, ta đặt kí tự đó trong cặp dấu '' hoặc "". Ví dụ, để viết kí tự 'a', chúng ta có thể sử dụng cú pháp cout << 'a'; hoặc cout << "a"; đều đúng.
Khi viết một chuỗi có nhiều hơn một kí tự, ta cần đặt chuỗi đó trong cặp dấu "". Ví dụ, để viết chuỗi "Bạn đã đăng nhập thành công", chúng ta sử dụng cú pháp cout << "Bạn đã đăng nhập thành công";.
III. Duyệt và tìm kiếm tuần tự trên chuỗi
1. Duyệt chuỗi
Để duyệt qua các phần tử trong chuỗi, chúng ta có thể sử dụng một vòng lặp từ vị trí đầu tiên đến vị trí cuối cùng của chuỗi. Lớp <string> cung cấp phương thức {Tên_chuỗi}.size() để lấy độ dài của chuỗi. Nhớ rằng các phần tử trong chuỗi được đánh số từ vị trí 0,
Do đó, cú pháp duyệt qua chuỗi như sau:
Chẳng hạn, để duyệt các phần tử của một chuỗi s từ đầu tới cuối chuỗi, ta viết như sau:
Nếu muốn duyệt qua một đoạn nhỏ trên chuỗi hoặc duyệt ngược từ cuối về đầu chuỗi, chúng ta có thể thay đổi vòng lặp theo ý muốn. Hãy thử suy nghĩ về vấn đề này và cách biến đổi vòng lặp phù hợp.
Ngoài ra, chúng ta cũng có thể duyệt qua tất cả các phần tử trong chuỗi bằng cách truy cập trực tiếp vào từng phần tử, như sau:
Ví dụ, muốn duyệt qua mọi phần tử của chuỗi s bất kỳ theo cách này, ta viết:
Dù vậy, phương pháp này chỉ cho phép duyệt từng phần tử của chuỗi theo trình tự từ trái qua phải và yêu cầu phải duyệt qua toàn bộ chuỗi. Do đó, nó không được ưu tiên như phương pháp đầu tiên.
2. Tìm kiếm tuần tự trên chuỗi
Vấn đề được đặt ra rất đơn giản: Chúng ta được cung cấp một chuỗi ký tự s chỉ bao gồm các chữ cái latin in thường và một ký tự chữ cái c bất kỳ. Nhiệm vụ là đếm số lần xuất hiện của ký tự c trong chuỗi s.
Bằng cách duyệt qua từng phần tử của chuỗi và sử dụng các toán tử phù hợp, chúng ta có thể giải quyết bài toán như sau:
Vấn đề tìm kiếm trên chuỗi có thể được thực hiện theo nhiều cách khác nhau, tùy thuộc vào việc hiểu rõ về cách đánh số thứ tự của các ký tự và cách duyệt qua các ký tự trong chuỗi.
Trong phần tiếp theo của bài viết, tôi sẽ trình bày về các thao tác xử lý chuỗi ký tự và giới thiệu một số bài toán áp dụng. Hãy cùng theo dõi để tìm hiểu thêm!