Bài tập 5 (B9_C#) Xây dựng lớp StringHelper

Sau khi hoàn thành bài tập này, bạn sẽ:

STTMục tiêuMô tả
1Xây dựng lớp StaticHiểu và xây dựng lớp StringHelper là lớp static (không thể khởi tạo) để chứa các phương thức tiện ích xử lý chuỗi
2Xử lý chuỗi nâng caoThực hiện các thao tác: viết hoa đầu từ, chuẩn hóa tên, đảo ngược chuỗi, đếm số từ
3Tạo mật khẩu ngẫu nhiênSử dụng RandomEnumerable.Repeat để tạo mật khẩu với độ dài tùy chỉnh
4Cắt chuỗi (Ellipsis)Xây dựng hàm cắt chuỗi và thêm dấu ... khi chuỗi quá dài
5Tái sử dụng mãXây dựng thư viện tiện ích (Utility) dùng chung cho nhiều ứng dụng khác

CÁC PHƯƠNG THỨC CẦN XÂY DỰNG

Phương thứcMô tảVí dụ
VietHoaChuCaiDau()Viết hoa chữ cái đầu mỗi từ“nguyễn văn a” → “Nguyễn Văn A”
ChuanHoaTen()Xóa khoảng trắng thừa + viết hoa đầu từ” nguyễn văn a ” → “Nguyễn Văn A”
TaoMatKhau()Tạo mật khẩu ngẫu nhiên có độ dài chỉ địnhTaoMatKhau(10) → “aB3!xY9@kL”
CatChuoi()Cắt chuỗi và thêm “…” nếu dài hơn giới hạn“Chuỗi dài quá” (20) → “Chuỗi dài…”
DemSoTu()Đếm số từ trong chuỗi“Học lập trình C#” → 3
DaoNguoc()Đảo ngược chuỗi“Hello” → “olleH”

KIẾN THỨC ÁP DỤNG

STT Kiến thức Áp dụng
1 Static Class Lớp StringHelper là static, chỉ chứa phương thức static
2 Chuỗi (string) Các thao tác: Trim(), Replace(), Split(), Substring()
3 Mảng (Array) Dùng mảng string[]char[] để xử lý chuỗi
4 Vòng lặp Duyệt mảng từ để viết hoa, đảo ngược
5 Linq Enumerable.Repeat() để tạo mật khẩu ngẫu nhiên
6 Random Tạo số ngẫu nhiên cho mật khẩu
7 StringBuilder Có thể dùng để tối ưu khi xử lý chuỗi dài

Helpers/StringHelper.cs

using System;
using System.Linq;  // Cần cho Enumerable.Repeat trong TaoMatKhau

/*
 * ============================================================
 * LỚP STRINGHELPER - TIỆN ÍCH XỬ LÝ CHUỖI
 * ============================================================
 * 
 * ĐẶC ĐIỂM:
 * - Lớp STATIC: Không cần khởi tạo đối tượng, gọi trực tiếp qua tên lớp
 * - Chứa các phương thức tiện ích (utility methods) để xử lý chuỗi
 * - Đặt trong namespace Bai5_StringHelper.Helpers
 */
namespace Bai5_StringHelper.Helpers
{
    public static class StringHelper
    {
        // ============================================================
        // 1. VIẾT HOA CHỮ CÁI ĐẦU MỖI TỪ
        // ============================================================
        // MỤC ĐÍCH: Chuyển đổi chuỗi thành dạng Title Case
        // Ví dụ: "ngUYỄN vĂN a" → "Nguyễn Văn A"
        public static string VietHoaChuCaiDau(string s)
        {
            // Kiểm tra chuỗi rỗng hoặc null để tránh lỗi
            if (string.IsNullOrEmpty(s)) return s;
            
            // Loại bỏ khoảng trắng đầu và cuối chuỗi
            s = s.Trim();
            
            // Tách chuỗi thành mảng các từ dựa trên khoảng trắng
            string[] words = s.Split(' ');
            
            // Duyệt từng từ trong mảng
            for (int i = 0; i < words.Length; i++)
            {
                // Bỏ qua từ rỗng (trường hợp nhiều khoảng trắng)
                if (!string.IsNullOrEmpty(words[i]))
                {
                    // Viết hoa chữ cái đầu + viết thường phần còn lại
                    // words[i][0]: lấy ký tự đầu tiên
                    // words[i].Substring(1): lấy phần còn lại từ vị trí 1
                    words[i] = char.ToUpper(words[i][0]) + words[i].Substring(1).ToLower();
                }
            }
            
            // Ghép các từ lại với nhau bằng khoảng trắng
            return string.Join(" ", words);
        }

        // ============================================================
        // 2. CHUẨN HÓA TÊN
        // ============================================================
        // MỤC ĐÍCH: Xóa khoảng trắng thừa + Viết hoa chuẩn tên
        // Ví dụ: "  Nguyễn   Văn   A  " → "Nguyễn Văn A"
        public static string ChuanHoaTen(string ten)
        {
            // Kiểm tra chuỗi rỗng hoặc null
            if (string.IsNullOrEmpty(ten)) return ten;
            
            // Bước 1: Xóa khoảng trắng đầu và cuối
            ten = ten.Trim();
            
            // Bước 2: Xóa khoảng trắng thừa giữa các từ
            // Lặp đến khi không còn 2 khoảng trắng liên tiếp
            while (ten.Contains("  "))
                ten = ten.Replace("  ", " ");  // Thay 2 spaces → 1 space
            
            // Bước 3: Gọi hàm viết hoa chữ cái đầu
            return VietHoaChuCaiDau(ten);
        }

        // ============================================================
        // 3. TẠO MẬT KHẨU NGẪU NHIÊN
        // ============================================================
        // MỤC ĐÍCH: Tạo chuỗi mật khẩu ngẫu nhiên với độ dài chỉ định
        // Ví dụ: TaoMatKhau(10) → "aB3@xY9#mN"
        public static string TaoMatKhau(int doDai = 8)  // Tham số mặc định = 8
        {
            // Chuỗi chứa tất cả ký tự cho phép trong mật khẩu
            // Gồm: Chữ hoa, chữ thường, số, và ký tự đặc biệt
            const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
            
            // Tạo đối tượng Random để sinh số ngẫu nhiên
            Random rand = new Random();
            
            /* 
             * Cơ chế tạo mật khẩu:
             * 1. Enumerable.Repeat(chars, doDai) 
             *    → Lặp lại chuỗi chars doDai lần
             * 2. .Select(s => s[rand.Next(s.Length)]) 
             *    → Mỗi lần chọn ngẫu nhiên 1 ký tự từ chuỗi chars
             * 3. .ToArray() 
             *    → Chuyển thành mảng ký tự
             * 4. new string(...) 
             *    → Tạo chuỗi từ mảng ký tự
             */
            return new string(Enumerable.Repeat(chars, doDai)
                .Select(s => s[rand.Next(s.Length)])
                .ToArray());
        }

        // ============================================================
        // 4. CẮT CHUỖI (THÊM "...")
        // ============================================================
        // MỤC ĐÍCH: Rút gọn chuỗi dài, thêm "..." vào cuối
        // Ví dụ: CatChuoi("Xin chào thế giới", 10) → "Xin chào..."
        public static string CatChuoi(string s, int maxLen)
        {
            // Kiểm tra chuỗi rỗng/null
            if (string.IsNullOrEmpty(s)) return s;
            
            // Nếu chuỗi đã ngắn hơn maxLen → giữ nguyên
            if (s.Length <= maxLen) return s;
            
            // Cắt chuỗi: lấy maxLen - 3 ký tự đầu + "..."
            // Trừ 3 để chừa chỗ cho dấu "..."
            return s.Substring(0, maxLen - 3) + "...";
        }

        // ============================================================
        // 5. ĐẾM SỐ TỪ TRONG CHUỖI
        // ============================================================
        // MỤC ĐÍCH: Đếm số lượng từ trong một câu
        // Ví dụ: DemSoTu("Hôm nay trời đẹp") → 4
        public static int DemSoTu(string s)
        {
            // Kiểm tra chuỗi rỗng, null hoặc chỉ có khoảng trắng
            if (string.IsNullOrWhiteSpace(s)) return 0;
            
            // Xóa khoảng trắng đầu/cuối
            s = s.Trim();
            
            /* 
             * Tách chuỗi thành mảng từ:
             * - Dùng ký tự phân cách là khoảng trắng ' '
             * - RemoveEmptyEntries: bỏ qua các phần tử rỗng
             * - Lấy độ dài mảng = số từ
             */
            return s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length;
        }

        // ============================================================
        // 6. ĐẢO NGƯỢC CHUỖI
        // ============================================================
        // MỤC ĐÍCH: Đảo ngược thứ tự các ký tự trong chuỗi
        // Ví dụ: DaoNguoc("Hello") → "olleH"
        public static string DaoNguoc(string s)
        {
            // Kiểm tra chuỗi rỗng/null
            if (string.IsNullOrEmpty(s)) return s;
            
            // Bước 1: Chuyển chuỗi thành mảng ký tự
            char[] chars = s.ToCharArray();
            
            // Bước 2: Đảo ngược mảng (thư viện .NET)
            Array.Reverse(chars);
            
            // Bước 3: Tạo chuỗi mới từ mảng đã đảo
            return new string(chars);
        }
    }
}

CÁCH SỬ DỤNG:

// Vì là static, gọi trực tiếp qua tên lớp
using Bai5_StringHelper.Helpers;

string ten = "  ngUYỄN   vĂN   a  ";
string tenChuan = StringHelper.ChuanHoaTen(ten);  // "Nguyễn Văn A"

string mk = StringHelper.TaoMatKhau(12);           // Mật khẩu 12 ký tự
int soTu = StringHelper.DemSoTu("Học C# thật vui"); // 4 từ

BẢNG TÓM TẮT CÁC PHƯƠNG THỨC:

 
 
Phương thứcTham sốKết quả trả vềChức năngVí dụ
VietHoaChuCaiDaustring sstringViết hoa đầu mỗi từ“ngUYỄN vĂN a” → “Nguyễn Văn A”
ChuanHoaTenstring tenstringXóa space thừa + viết hoa chuẩn” Nguyễn Văn A ” → “Nguyễn Văn A”
TaoMatKhauint doDai = 8stringTạo mật khẩu ngẫu nhiênTaoMatKhau(10) → “aB3@xY9#mN”
CatChuoistring s, int maxLenstringCắt chuỗi + thêm “…”“Xin chào thế giới”, 10 → “Xin chào…”
DemSoTustring sintĐếm số từ trong chuỗi“Hôm nay trời đẹp” → 4
DaoNguocstring sstringĐảo ngược chuỗi“Hello” → “olleH”

Program.cs

using System;                          // Cung cấp các kiểu dữ liệu cơ bản, Console,...
using Bai5_StringHelper.Helpers;       // Import namespace chứa lớp StringHelper

/*
 * ============================================================
 * CHƯƠNG TRÌNH TEST LỚP STRINGHELPER
 * ============================================================
 * 
 * MỤC ĐÍCH: 
 * - Kiểm tra (test) tất cả các phương thức của lớp StringHelper
 * - Minh họa cách sử dụng các hàm xử lý chuỗi
 * - Hiển thị kết quả ra màn hình Console
 */
namespace Bai5_StringHelper
{
    class Program
    {
        /* 
         * Phương thức Main - Điểm bắt đầu của chương trình
         * static: Không cần tạo đối tượng Program để gọi
         * void: Không trả về giá trị
         * string[] args: Tham số dòng lệnh (không sử dụng trong bài này)
         */
        static void Main(string[] args)
        {
            // ============================================================
            // CÀI ĐẶT HIỂN THỊ TIẾNG VIỆT
            // ============================================================
            // Thiết lập encoding cho Console để hiển thị đúng tiếng Việt
            // UTF8 hỗ trợ các ký tự có dấu như: á, à, ả, ã, ạ,...
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            
            // In tiêu đề chương trình với ký tự xuống dòng \n
            Console.WriteLine("===== BÀI TẬP 5: LỚP STRINGHELPER =====\n");

            // ============================================================
            // TEST 1: VIẾT HOA CHỮ CÁI ĐẦU
            // ============================================================
            // Mục đích: Kiểm tra chức năng viết hoa chữ cái đầu mỗi từ
            Console.WriteLine("1. Viết hoa chữ cái đầu:");
            
            string s1 = "nguyễn văn a";    // Chuỗi đầu vào (viết thường)
            Console.WriteLine($"   Input: '{s1}'");
            
            // Gọi phương thức VietHoaChuCaiDau từ lớp StringHelper (static)
            // Kết quả: "Nguyễn Văn A"
            Console.WriteLine($"   Output: '{StringHelper.VietHoaChuCaiDau(s1)}'");

            // ============================================================
            // TEST 2: CHUẨN HÓA TÊN
            // ============================================================
            // Mục đích: Xóa khoảng trắng thừa + viết hoa đúng tên
            Console.WriteLine("\n2. Chuẩn hóa tên:");
            
            // Chuỗi có nhiều khoảng trắng thừa ở đầu, giữa và cuối
            string s2 = "  nguyễn   văn   a  ";
            Console.WriteLine($"   Input: '{s2}'");
            
            // Gọi ChuanHoaTen: loại bỏ space thừa và viết hoa chuẩn
            // Kết quả: "Nguyễn Văn A"
            Console.WriteLine($"   Output: '{StringHelper.ChuanHoaTen(s2)}'");

            // ============================================================
            // TEST 3: TẠO MẬT KHẨU NGẪU NHIÊN
            // ============================================================
            // Mục đích: Sinh mật khẩu ngẫu nhiên với độ dài chỉ định
            Console.WriteLine("\n3. Tạo mật khẩu:");
            
            // Gọi TaoMatKhau với tham số 10 (độ dài 10 ký tự)
            // Mỗi lần chạy sẽ cho kết quả khác nhau
            string pass = StringHelper.TaoMatKhau(10);
            Console.WriteLine($"   Mật khẩu: {pass}");
            
            // Lưu ý: Nếu không truyền tham số, mặc định sẽ là 8 ký tự
            // string pass2 = StringHelper.TaoMatKhau(); // Mật khẩu 8 ký tự

            // ============================================================
            // TEST 4: CẮT CHUỖI (THÊM ...)
            // ============================================================
            // Mục đích: Rút ngắn chuỗi dài, thêm "..." vào cuối
            Console.WriteLine("\n4. Cắt chuỗi:");
            
            string s3 = "Đây là một chuỗi rất dài cần phải cắt ngắn";
            Console.WriteLine($"   Input: '{s3}'");
            
            // CatChuoi(s3, 20): Giữ tối đa 20 ký tự, thêm "..."
            // Kết quả: "Đây là một chuỗi..."
            Console.WriteLine($"   Output: '{StringHelper.CatChuoi(s3, 20)}'");

            // ============================================================
            // TEST 5: ĐẾM SỐ TỪ
            // ============================================================
            // Mục đích: Đếm chính xác số từ trong một câu
            Console.WriteLine("\n5. Đếm số từ:");
            
            // Chuỗi có nhiều khoảng trắng thừa giữa các từ
            string s4 = "  Học   lập trình  C#  ";
            Console.WriteLine($"   Input: '{s4}'");
            
            // DemSoTu: bỏ qua space thừa, đếm từ thực tế
            // Kết quả: 4 (Học, lập, trình, C#)
            Console.WriteLine($"   Số từ: {StringHelper.DemSoTu(s4)}");

            // ============================================================
            // TEST 6: ĐẢO NGƯỢC CHUỖI
            // ============================================================
            // Mục đích: Đảo ngược thứ tự các ký tự trong chuỗi
            Console.WriteLine("\n6. Đảo ngược chuỗi:");
            
            string s5 = "Hello C#";
            Console.WriteLine($"   Input: '{s5}'");
            
            // DaoNguoc: Đảo ngược toàn bộ chuỗi
            // Kết quả: "#C olleH"
            Console.WriteLine($"   Output: '{StringHelper.DaoNguoc(s5)}'");

            // ============================================================
            // KẾT THÚC CHƯƠNG TRÌNH
            // ============================================================
            Console.WriteLine("\nNhấn phím bất kỳ để thoát...");
            Console.ReadKey();  // Dừng màn hình, chờ người dùng nhấn phím
        }
    }
}

BẢNG TÓM TẮT CÁC TEST:

TestPhương thứcĐầu vàoKết quả mong đợiChức năng
1VietHoaChuCaiDau“nguyễn văn a”“Nguyễn Văn A”Viết hoa đầu từ
2ChuanHoaTen” nguyễn văn a ““Nguyễn Văn A”Chuẩn hóa tên
3TaoMatKhau10“aB3@xY9#mN” (random)Tạo mật khẩu
4CatChuoi“Đây là một chuỗi rất dài cần phải cắt ngắn”, 20“Đây là một chuỗi…”Cắt chuỗi
5DemSoTu” Học lập trình C# “4Đếm số từ
6DaoNguoc“Hello C#”“#C olleH”Đảo ngược