System.String có hàng chục phương thức. Trang này trình bày những phương thức gánh phần lớn công việc trong code thực tế, cùng các tùy chọn và cạm bẫy đáng chú ý. Có một quy tắc áp dụng cho tất cả: chuỗi là bất biến (immutable), nên mọi phương thức đều trả về chuỗi mới (hoặc một giá trị) và giữ nguyên chuỗi gốc. Viết s.Trim(); trên một dòng riêng không làm gì cả; hãy viết s = s.Trim();.
Split
Split tách một chuỗi thành string[] tại mỗi dấu phân cách:
Đầu ra:
3
apple
banana
cherry
red/green/ blue/yellow
INFO/started/ready
Để ý " blue": Split cắt đúng tại dấu phân cách và giữ lại mọi khoảng trắng. Hai tùy chọn xử lý những việc dọn dẹp thường gặp:
Đầu ra:
5
4
c#|dotnet|linq
key=[Subject] value=[Re: Meeting: Friday]
3
RemoveEmptyEntries bỏ các phần có độ dài bằng 0 nhưng không bỏ các phần chỉ toàn khoảng trắng (" " vẫn còn ở trên). .NET 5 bổ sung StringSplitOptions.TrimEntries, và có thể kết hợp cả hai: tags.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries) cho kết quả sạch chỉ với một lời gọi. Truyền null làm dấu phân cách sẽ tách theo mọi khoảng trắng, đây là cách thường dùng để tách văn bản thành các từ.
Tách theo một char (Split(',')) không cần mảng. Các overload nhận một char kèm tùy chọn, hoặc một string, có từ .NET Core 2.0; các dạng mảng dùng ở trên chạy ở mọi nơi, kể cả .NET Framework và Unity.
Replace
Replace thay thế mọi lần xuất hiện của một ký tự hoặc chuỗi con:
Đầu ra:
5551234567
555.123.4567
Cats and dogs and CATS
dogs and dogs and dogs
dogs and cats and CATS
too many spaces
Overload có đối số StringComparison có từ .NET Core 2.0. Trên .NET Framework, thay thế không phân biệt hoa thường được thực hiện bằng Regex.Replace(text, Regex.Escape(find), replacement, RegexOptions.IgnoreCase). Thay bằng "" là cách xóa ký tự, và nối nhiều lời gọi Replace liên tiếp là ổn khi chỉ có vài phép thay thế.
Contains, IndexOf, StartsWith và EndsWith
Các phương thức này dùng để tìm kiếm. Contains trả lời có hoặc không; IndexOf và LastIndexOf trả về một vị trí, hoặc -1 khi không khớp; StartsWith và EndsWith kiểm tra hai đầu chuỗi.
Đầu ra:
True
False
True
True
8
30
28
-1
16
False
True
True
Mặc định tất cả đều phân biệt hoa thường. Contains(string, StringComparison) có từ .NET Core 2.1; dạng IndexOf(...) >= 0 chạy trên mọi phiên bản, đó là lý do bạn hay thấy nó trong code cũ. IndexOfAny(new[] { ',', ';' }) tìm ký tự đầu tiên trong số nhiều ký tự.
Một lưu ý về culture: khi không có StringComparison, StartsWith, EndsWith, IndexOf(string) và CompareTo dùng quy tắc phụ thuộc culture, còn Contains, Replace và IndexOf(char) so sánh theo thứ tự mã (ordinal). Truyền tường minh StringComparison.Ordinal hoặc OrdinalIgnoreCase sẽ loại bỏ sự mơ hồ, và các công cụ phân tích code cũng khuyên làm vậy.
Trim, TrimStart và TrimEnd
Trim xóa khoảng trắng (dấu cách, tab, xuống dòng) ở cả hai đầu. TrimStart và TrimEnd xóa ở một đầu. Khi được truyền các ký tự, chúng xóa những ký tự đó thay vì khoảng trắng:
Đầu ra:
[ana@example.com]
[ana@example.com \n]
[ x]
SALE
7
path/to/dir
1,234.50
Trim chỉ tác động lên hai đầu; khoảng trắng bên trong chuỗi được giữ nguyên. TrimStart('0') trên "000" trả về chuỗi rỗng, nên hãy phân tích chuỗi số bằng int.Parse thay vì tự bỏ các số 0.
ToUpper và ToLower
Đầu ra:
MAYA LOPEZ
maya lopez
MAYA LOPEZ
Coffee
ToUpper và ToLower theo culture hiện tại, nên trong tiếng Thổ Nhĩ Kỳ "i".ToUpper() là chữ İ hoa có dấu chấm, không phải I. Với định danh, khóa và tên tệp, hãy dùng ToUpperInvariant và ToLowerInvariant. Khi so sánh, hãy dùng StringComparison thay vì đổi hoa thường (xem chuỗi). Để viết hoa chữ cái đầu mỗi từ, có CultureInfo.CurrentCulture.TextInfo.ToTitleCase(text), dù nó bỏ qua những từ đã viết hoa toàn bộ.
PadLeft và PadRight
Đệm chuỗi là thêm ký tự cho đến khi chuỗi đạt độ rộng tổng mong muốn. Rất tiện cho đầu ra có độ rộng cố định và cho việc đệm số 0 vào mã:
Đầu ra:
000042
[Tea ]
[ Tea]
Too long already
Espresso.. 2.40
Latte..... 3.60
Mocha..... 3.95
Căn lề trong nội suy chuỗi ({name,-10}) làm cùng việc này ngay tại chỗ.
Join và Concat
string.Join đặt một dấu phân cách giữa các phần tử của bất kỳ collection nào. string.Concat nối mà không có dấu phân cách:
Đầu ra:
Ana, Ben, Chloe
1 + 2 + 3
True
2026-09
AnaBenChloe
Ana, Ben and Chloe
Join là cách đúng để tạo một danh sách có dấu phân cách: không có dấu phân cách thừa ở cuối cần xóa, và kết quả được tạo trong một lượt. Nó gọi ToString() trên từng phần tử, nên dùng được cả với số và đối tượng.
Reverse, Insert và Remove
Không có phương thức string.Reverse nào trả về chuỗi. Có hai cách thường dùng:
Đầu ra:
desserts
desserts
True
2026/Q3-09
Hello
HelloWorld
Riêng word.Reverse() trả về một IEnumerable<char>, không phải chuỗi; in nó ra chỉ thấy tên kiểu. Cả hai cách đều đảo các đơn vị mã UTF-16, làm hỏng những ký tự gồm hai đơn vị (hầu hết emoji) và chữ cái có dấu kết hợp.
Tra cứu nhanh
| Việc cần làm | Phương thức |
|---|---|
| Tách thành các phần | s.Split(','), s.Split(new[] {',', ';'}, StringSplitOptions.RemoveEmptyEntries) |
| Thay thế tất cả | s.Replace("a", "b") |
| Kiểm tra có chứa | s.Contains("x"), s.Contains("x", StringComparison.OrdinalIgnoreCase) |
| Vị trí | s.IndexOf("x"), s.LastIndexOf('x') (-1 nếu không có) |
| Bắt đầu hoặc kết thúc bằng | s.StartsWith("x"), s.EndsWith(".pdf", StringComparison.OrdinalIgnoreCase) |
| Xóa khoảng trắng ở hai đầu | s.Trim(), s.TrimStart(), s.TrimEnd() |
| Đổi hoa thường | s.ToUpper(), s.ToLowerInvariant() |
| Đệm đến độ rộng | s.PadLeft(6, '0'), s.PadRight(10) |
| Nối một collection | string.Join(", ", items) |
| Lấy một phần chuỗi | s.Substring(start, length) |
| Chèn hoặc xóa | s.Insert(i, "x"), s.Remove(i, count) |
| Kiểm tra null hoặc rỗng | string.IsNullOrWhiteSpace(s) |
Câu hỏi thường gặp
Làm sao tách chuỗi trong C#?
text.Split(',') trả về một string[] gồm các phần nằm giữa các dấu phẩy. Truyền nhiều dấu phân cách dưới dạng mảng (Split(new[] { ',', ';' })), dấu phân cách là chuỗi bằng Split(new[] { ", " }, StringSplitOptions.None), và StringSplitOptions.RemoveEmptyEntries để bỏ các phần rỗng sinh ra khi dấu phân cách bị lặp. .NET 5 bổ sung StringSplitOptions.TrimEntries để cắt khoảng trắng của từng phần.
Làm sao kiểm tra một chuỗi có chứa chuỗi khác hay không, không phân biệt hoa thường?
Trên .NET Core 2.1 trở đi: text.Contains("error", StringComparison.OrdinalIgnoreCase). Trên .NET Framework, vốn không có overload đó, hãy dùng text.IndexOf("error", StringComparison.OrdinalIgnoreCase) >= 0. Tránh text.ToLower().Contains(...), cách này tạo thêm một bản sao và có thể hoạt động sai ở một số culture.
String.Replace có thay đổi chuỗi gốc trong C# không?
Không. Chuỗi là bất biến, nên Replace trả về một chuỗi mới với mọi lần xuất hiện đã được thay thế và giữ nguyên chuỗi gốc. Hãy viết s = s.Replace("old", "new");. Nó thay thế tất cả các lần xuất hiện, không chỉ lần đầu; để chỉ thay lần đầu tiên, hãy tìm nó bằng IndexOf rồi dựng lại chuỗi, hoặc gọi Replace trên một instance Regex với số lần là 1.
IndexOf trả về gì nếu không tìm thấy chuỗi?
-1. Mọi kết quả từ 0 trở lên là vị trí (bắt đầu từ 0) của lần khớp đầu tiên. Luôn kiểm tra -1 trước khi dùng kết quả làm chỉ số, vì Substring(-1) sẽ ném ngoại lệ còn Substring(-1 + 1) lại âm thầm trả về cả chuỗi. LastIndexOf hoạt động tương tự nhưng tìm từ cuối.
Làm sao đảo ngược chuỗi trong C#?
Chép nó vào một mảng char, đảo ngược mảng, rồi tạo chuỗi mới: char[] a = s.ToCharArray(); Array.Reverse(a); string r = new string(a);. Với LINQ, new string(s.Reverse().ToArray()) làm điều tương tự. Cả hai cách đều đảo các đơn vị UTF-16, nên emoji và dấu kết hợp có thể bị xáo trộn.