Xâu ký tự trong C++

Định nghĩa và khái niệm cơ bản

Trong ngôn ngữ lập trình C++, xâu ký tự (hay còn gọi là chuỗi ký tự) là một loại biến đặc biệt, được sử dụng để lưu trữ và xử lý một chuỗi các ký tự.

Xâu ký tự được biểu diễn bằng một mảng các ký tự, được kết thúc bằng ký tự NULL (‘\0’). Ký tự NULL này được sử dụng để đánh dấu kết thúc của chuỗi, giúp cho các hàm xử lý xâu ký tự như strlen, strcpy, strcat, v.v… có thể hoạt động đúng và an toàn.

Một số khái niệm cơ bản liên quan đến xâu ký tự trong C++:

  • Độ dài của xâu ký tự: là số ký tự trong chuỗi (không tính ký tự NULL).
  • Ký tự trong xâu: được đánh số từ 0 đến độ dài xâu trừ 1.
  • Xâu rỗng: là xâu ký tự không chứa bất kỳ ký tự nào, chỉ có ký tự NULL.
  • Xâu hợp lệ: là xâu ký tự chứa ít nhất một ký tự và kết thúc bằng ký tự NULL.
  • Xâu không hợp lệ: là xâu ký tự không kết thúc bằng ký tự NULL hoặc không chứa bất kỳ ký tự nào.

Khai báo và khởi tạo xâu ký tự trong C++

  1. Cách khai báo xâu ký tự trong C++:

Có thể khai báo xâu ký tự trong C++ bằng cách sử dụng một mảng ký tự. Cú pháp khai báo xâu ký tự như sau:

char ten_xau[size];

Trong đó:

  • ten_xau: là tên của xâu ký tự, có thể tự đặt.
  • size: là số lượng ký tự tối đa có thể lưu trữ trong xâu ký tự (không tính ký tự NULL).

Ví dụ:

char ho_ten[50]; // khai báo một xâu ký tự tên ho_ten, có thể chứa tối đa 49 ký tự (không tính ký tự NULL).

  1. Cách khởi tạo xâu ký tự trong C++:

Có thể khởi tạo xâu ký tự bằng cách gán một chuỗi ký tự vào mảng ký tự đại diện cho xâu. Cú pháp khởi tạo xâu ký tự như sau:

char ten_xau[] = "noi dung chuoi";

Ví dụ:

char ho_ten[] = "Nguyen Van A"; // khởi tạo xâu ký tự ho_ten với nội dung là "Nguyen Van A".

  1. Cách thay đổi giá trị của một xâu ký tự trong C++:

Để thay đổi giá trị của một xâu ký tự trong C++, ta có thể sử dụng các hàm và phép toán xử lý xâu ký tự như strcpy, strcat, v.v… hoặc gán giá trị mới cho từng phần tử trong mảng ký tự đại diện cho xâu.

Ví dụ:

char ho_ten[50] = "Nguyen Van A"; // khởi tạo xâu ký tự ho_ten với nội dung là "Nguyen Van A".
ho_ten[7] = 'B'; // thay đổi ký tự thứ 8 trong xâu ký tự từ 'V' thành 'B'.

Hoặc sử dụng hàm strcpy để thay đổi toàn bộ nội dung của xâu:

char ho_ten[50] = "Nguyen Van A"; // khởi tạo xâu ký tự ho_ten với nội dung là "Nguyen Van A".
strcpy(ho_ten, "Le Thi B"); // thay đổi nội dung của xâu ho_ten thành "Le Thi B".

Các phép toán trên xâu ký tự trong C++

Trong C++, có rất nhiều phép toán về xâu ký tự. Dưới đây là một số phép toán thông dụng:

  1. Gán xâu ký tự: string str = "Hello world";
  2. Nối xâu ký tự: string str1 = "Hello"; string str2 = "world"; str1 += str2; hoặc string str3 = str1 + str2;
  3. So sánh xâu ký tự: if (str1 == str2) { ... } hoặc if (str1 < str2) { ... } và nhiều phép toán so sánh khác như !=, >, <=, >=.
  4. Độ dài xâu ký tự: int len = str1.length(); hoặc int len = str1.size();
  5. Truy xuất ký tự trong xâu: char c = str1[0]; hoặc char c = str1.at(0);
  6. Chuyển đổi xâu ký tự thành số nguyên: int num = stoi(str1);
  7. Chuyển đổi số nguyên thành xâu ký tự: string str4 = to_string(num);
  8. Tìm kiếm chuỗi con trong xâu: int pos = str1.find("world"); hoặc int pos = str1.find("world", 6);
  9. Cắt xâu ký tự: string sub_str = str1.substr(6, 5);
  10. Thay thế chuỗi con trong xâu: str1.replace(pos, 5, "universe");
  11. Xoá các ký tự trắng ở đầu và cuối xâu: str1.erase(0, str1.find_first_not_of(" ")); str1.erase(str1.find_last_not_of(" ") + 1);
  12. Chuyển đổi tất cả các ký tự trong xâu thành chữ hoa hoặc chữ thường: transform(str1.begin(), str1.end(), str1.begin(), ::toupper); hoặc transform(str1.begin(), str1.end(), str1.begin(), ::tolower);
  13. Chèn chuỗi con vào xâu ký tự: str1.insert(6, "new");
  14. Chuyển đổi các ký tự trong xâu thành các giá trị ASCII tương ứng: for(char c : str1) { int ascii_val = (int)c; ... }
  15. Tách xâu thành một mảng các xâu con dựa trên ký tự phân tách: vector<string> tokens; stringstream ss(str1); string token; while(getline(ss, token, ',')) { tokens.push_back(token); }
  16. Tách xâu thành một mảng các xâu con dựa trên một chuỗi phân tách: vector<string> tokens; boost::split(tokens, str1, boost::is_any_of(" ,.")); (yêu cầu thư viện Boost)
  17. Xoá chuỗi con trong xâu: str1.erase(str1.find("world"), 5);
  18. Thực hiện các thay thế tất cả các chuỗi con trong xâu: std::regex pattern("world"); str1 = std::regex_replace(str1, pattern, "universe"); (yêu cầu thư viện regex)
  19. Kiểm tra xem xâu có bắt đầu bằng một chuỗi con nào đó hay không: if (str1.compare(0, 5, "Hello") == 0) { ... }
  20. Lấy một xâu con từ vị trí bắt đầu đến vị trí kết thúc: string sub_str = str1.substr(0, 5);
  21. Chèn một xâu vào xâu khác từ vị trí bắt đầu: str1.insert(5, "new string");
  22. Chuyển đổi một xâu thành một mảng các ký tự: char char_array[100]; strcpy(char_array, str1.c_str());
  23. Kiểm tra xem xâu có kết thúc bằng một chuỗi con nào đó hay không: if (str1.compare(str1.length() - 5, 5, "world") == 0) { ... }

Lưu ý rằng, để sử dụng các phép toán trên, bạn cần bao gồm các thư viện cần thiết như: <regex>, <cstring><boost/algorithm/string.hpp> (đối với phép toán số 16). ngoài ra cần thêm các thư viện: <algorithm>, <sstream>, <vector><iostream>.

Ví dụ về xâu ký tự trong C++

Vi dụ 1. Sắp xếp xâu theo thứ tự từ điển.

Để sắp xếp xâu theo thứ tự từ điển trong C++, bạn có thể sử dụng hàm sort của thư viện <algorithm> hoặc sử dụng hàm sort của lớp string.

Ví dụ sử dụng hàm sort của thư viện <algorithm>:

#include <iostream>
#include <algorithm>
#include <string>

using namespace std;

int main() {
    string s = "hello world";
    sort(s.begin(), s.end());
    cout << s << endl;
    return 0;
}

Ví dụ sử dụng hàm sort của lớp string:

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s = "hello world";
    sort(s.begin(), s.end());
    cout << s << endl;
    return 0;
}

Cả hai ví dụ đều sắp xếp xâu “hello world” theo thứ tự từ điển, kết quả đầu ra sẽ là ” dehllloorw”. Chú ý rằng hàm sort của lớp string chỉ có sẵn từ phiên bản C++11 trở lên.

Ví dụ 2. Tìm tất cả các chuỗi con của một xâu.

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s = "abc";
    int len = s.length();

    for (int i = 0; i < len; i++) {
        for (int j = i; j < len; j++) {
            cout << s.substr(i, j-i+1) << endl;
        }
    }

    return 0;
}

Trong ví dụ này, hai vòng lặp lồng nhau duyệt qua tất cả các cặp vị trí (i, j) trong xâu và lấy chuỗi con bắt đầu từ vị trí i và kết thúc tại vị trí j, sử dụng hàm substr. Kết quả đầu ra sẽ là tất cả các chuỗi con của xâu “abc”:

a
ab
abc
b
bc
c

Chú ý rằng xâu con có thể có độ dài từ 1 đến độ dài của xâu gốc, do đó chúng ta cần sử dụng hai biến lặp i và j để duyệt qua tất cả các chuỗi con có thể có.

Ví dụ 3. Tìm tất cả các lần xuất hiện của một chuỗi con trong một xâu

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s = "hello world";
    string t = "l";
    int pos = s.find(t);

    while (pos != string::npos) {
        cout << "Tìm thấy ở vị trí " << pos << endl;
        pos = s.find(t, pos + 1);
    }

    return 0;
}

Trong ví dụ này, chúng ta sử dụng hàm find để tìm vị trí đầu tiên của chuỗi con “l” trong xâu “hello world”. Nếu chuỗi con không tồn tại trong xâu, hàm find sẽ trả về giá trị string::npos. Nếu chuỗi con tồn tại, chúng ta sử dụng một vòng lặp để tìm tất cả các vị trí xuất hiện của chuỗi con bằng cách thay đổi tham số thứ hai của hàm find thành vị trí kế tiếp của chuỗi con trong xâu.

Ví dụ 4. Chuyển xâu ký tự thành ký tự hoa và ngược lại

Để chuyển đổi các ký tự thường thành ký tự hoa và ngược lại trong một chuỗi trong C++, bạn có thể sử dụng hàm toupper()tolower() trong thư viện ctype.h.

#include <iostream>
#include <ctype.h>

using namespace std;

int main() {
    string str = "Hello World";
    
    // Chuyển đổi các ký tự thường thành ký tự hoa
    for (int i = 0; i < str.size(); i++) {
        str[i] = toupper(str[i]);
    }
    cout << "Chuỗi sau khi chuyển thành ký tự hoa: " << str << endl;

    // Chuyển đổi các ký tự hoa thành ký tự thường
    for (int i = 0; i < str.size(); i++) {
        str[i] = tolower(str[i]);
    }
    cout << "Chuỗi sau khi chuyển thành ký tự thường: " << str << endl;
    
    return 0;
}

Ví dụ 5. Xoá các khoảng trắng thừa ở đầu và cuối xâu

Để xoá các khoảng trắng thừa ở đầu và cuối xâu, ta có thể sử dụng hàm trim() của thư viện chuỗi trong C++.

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string s = "    This is a string with extra spaces.   ";
    s = trim(s);
    cout << s << endl;
    return 0;
}

Lưu ý: Hàm trim() không nằm trong thư viện chuẩn của C++, bạn cần định nghĩa nó trước khi sử dụng. Dưới đây là một phiên bản đơn giản của hàm trim():

#include <algorithm>
#include <cctype>
#include <string>

std::string trim(const std::string& str)
{
    auto first = str.find_first_not_of(' ');
    if (first == std::string::npos) {
        return "";
    }
    auto last = str.find_last_not_of(' ');
    return str.substr(first, last - first + 1);
}

Đoạn code trên sẽ tìm vị trí đầu tiên của kí tự không phải khoảng trắng trong chuỗi, sau đó tìm vị trí cuối cùng của kí tự không phải khoảng trắng. Cuối cùng, nó trả về một chuỗi con của chuỗi ban đầu từ vị trí đầu đến vị trí cuối đó.

Ví dụ 6. Đảo ngược một xâu

Để đảo ngược một xâu trong C++, ta có thể sử dụng hàm reverse() của thư viện chuỗi.

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

int main()
{
    string s = "Hello World!";
    reverse(s.begin(), s.end());
    cout << s << endl;
    return 0;
}

Lưu ý: Hàm reverse() nằm trong thư viện <algorithm>. Ta cần phải include thư viện này để sử dụng hàm reverse().

Nếu không muốn sử dụng hàm reverse() thì ta có thể tự viết hàm đảo ngược xâu bằng cách sử dụng vòng lặp.

#include <iostream>
#include <string>

using namespace std;

string reverseString(string s) {
    int n = s.length();
    for(int i=0; i<n/2; i++) {
        swap(s[i], s[n-i-1]);
    }
    return s;
}

int main()
{
    string s = "Hello World!";
    s = reverseString(s);
    cout << s << endl;
    return 0;
}

Lưu ý: Hàm swap() nằm trong thư viện chuẩn của C++. Ta có thể sử dụng hàm này để hoán đổi giá trị của hai biến.

Ví dụ 7. Kiểm tra chuỗi đối xứng

Kiểm tra xem một xâu có phải là chuỗi đối xứng hay không?

Để kiểm tra xem một xâu có phải là chuỗi đối xứng hay không, ta có thể so sánh xâu ban đầu với xâu đảo ngược của nó. Nếu hai xâu này giống nhau, thì xâu ban đầu là chuỗi đối xứng.

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

bool isPalindrome(string s) {
    string reversed = s;
    reverse(reversed.begin(), reversed.end());
    return s == reversed;
}

int main()
{
    string s1 = "racecar";
    string s2 = "hello";
    if(isPalindrome(s1)) {
        cout << s1 << " is a palindrome." << endl;
    } else {
        cout << s1 << " is not a palindrome." << endl;
    }
    if(isPalindrome(s2)) {
        cout << s2 << " is a palindrome." << endl;
    } else {
        cout << s2 << " is not a palindrome." << endl;
    }
    return 0;
}

Lưu ý: Để kiểm tra chuỗi đối xứng, ta cần viết hàm isPalindrome() để so sánh xâu ban đầu với xâu đảo ngược của nó.

Ví dụ 8. Tìm xâu con lớn nhất có chứa các ký tự không trùng nhau

Dưới đây là mã nguồn để tìm xâu con lớn nhất có chứa các ký tự không trùng nhau trong một xâu bằng cách sử dụng hai con trỏ và một bộ đếm:

#include <iostream>
#include <string>
#include <unordered_set>

using namespace std;

string longestSubstring(string s) {
    int n = s.length();
    int left = 0, right = 0, maxLen = 0, start = 0;
    unordered_set<char> charSet;
    while(right < n) {
        if(charSet.count(s[right]) == 0) {
            charSet.insert(s[right]);
            right++;
        } else {
            charSet.erase(s[left]);
            left++;
        }
        if(charSet.size() > maxLen) {
            maxLen = charSet.size();
            start = left;
        }
    }
    return s.substr(start, maxLen);
}

int main()
{
    string s = "abcabcbb";
    string longest = longestSubstring(s);
    cout << "Longest substring with non-repeating characters: " << longest << endl;
    return 0;
}

Ví dụ 9. Tìm xâu con chung dài nhất của hai xâu

Để tìm xâu con chung dài nhất của hai xâu, chúng ta có thể sử dụng thuật toán Dynamic Programming.

#include <bits/stdc++.h>
using namespace std;

string longestCommonSubsequence(string s1, string s2) {
    int m = s1.length();
    int n = s2.length();
    vector<vector<int>> dp(m+1, vector<int>(n+1, 0));

    // tính độ dài xâu con chung dài nhất của hai xâu
    for(int i = 1; i <= m; i++) {
        for(int j = 1; j <= n; j++) {
            if(s1[i-1] == s2[j-1])
                dp[i][j] = dp[i-1][j-1] + 1;
            else
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
        }
    }

    // truy vết xâu con chung dài nhất
    string res = "";
    int i = m, j = n;
    while(i > 0 && j > 0) {
        if(s1[i-1] == s2[j-1]) {
            res += s1[i-1];
            i--;
            j--;
        }
        else if(dp[i-1][j] > dp[i][j-1])
            i--;
        else
            j--;
    }
    reverse(res.begin(), res.end());
    return res;
}

int main() {
    string s1 = "abcdaf";
    string s2 = "acbcf";
    cout << longestCommonSubsequence(s1, s2) << endl; // đáp án: abcf
    return 0;
}

Ví dụ 10. Tìm tất cả các xâu con có độ dài k cho trước

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string str = "abcdefg";
    int k = 3;

    // Duyệt qua tất cả các chỉ số của xâu ban đầu
    for (int i = 0; i <= str.length() - k; i++)
    {
        // In ra các xâu con có độ dài k bắt đầu từ chỉ số i
        cout << str.substr(i, k) << endl;
    }

    return 0;
}

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *