字串雖然天天都在用,但C#其實藏了很多方便的功能,像是寫路徑不用狂打反斜線的「逐字字串」,或是像填空一樣直覺的「字串插值」。這篇筆記比較像是開發備忘錄,忘記怎麼寫的時候再回來翻一下、Copy程式碼就好。重點是知道有這些工具可以用,多寫幾次手感自然就出來了!
【C#學習筆記】05《元組(Tuple)與忽略(Discard)》
// 一般字串
var s1 = "This is a string";
// \t 代表 Tab 縮排字元
var s2 = "This is\t a string";
// \" 代表字串中的雙引號 "
var s3 = "This is a \"string\"";
// \\ 代表字串中的反斜線 \
var s4 = "This is a \\string";
// Windows 路徑寫法
// 因為 \ 是逸出字元,所以需要寫成 \\
var s5 = "C:\\Program Files";
// @ 代表逐字字串(Verbatim String)
// 不會處理逸出字元,因此 \ 不需要寫成 \\
var s6 = @"C:\Program Files";
// \n 代表換行
var s7 = "This is string 1\nThis is string 2";
// 逐字字串可以直接換行
var s8 = @"This is string 1
This is string 2";
// 使用字串插值前準備的變數
int i = 1;
bool b = false;
double d = 3.14;
// $ 代表插值字串(Interpolated String)
// 可以直接在字串內放入變數
var s9 = $"This is {i}";
// 字串串接
// 將 s1 與 "!" 接在一起
var s10 = s1 + "!";
// 輸出 s10
Console.WriteLine($"s10 = {s10}");
// 使用 + 將不同型別資料串接成字串
// 最終都會自動轉成 string
var s11 = $"This is " + i + b + d;
// 輸出 s11
Console.WriteLine($"s11 = {s11}");
輸出結果
Console.WriteLine($"s1 = {s1}");
// 結果: s1 = This is a string
Console.WriteLine($"s2 = {s2}");
// 結果: s2 = This is a string
// \t 會產生 Tab 間距
Console.WriteLine($"s3 = {s3}");
// 結果: s3 = This is a "string"
Console.WriteLine($"s4 = {s4}");
// 結果: s4 = This is a \string
Console.WriteLine($"s5 = {s5}");
// 結果: s5 = C:\Program Files
Console.WriteLine($"s6 = {s6}");
// 結果: s6 = C:\Program Files
Console.WriteLine($"s7 = {s7}");
// 結果:
// s7 = This is string 1
// This is string 2
Console.WriteLine($"s8 = {s8}");
// 結果:
// s8 = This is string 1
// This is string 2
Console.WriteLine($"s9 = {s9}");
// 結果: s9 = This is 1
Console.WriteLine($"s11 = {s11}");
// 結果: s11 = This is 1False3.14
// int、bool、double 會自動轉成字串後串接
// Raw String Literal(原始字串)
// 使用 """ 包住字串
// 不需要逸出雙引號
string singleLine = """Friends say "hello" as they pass by.""";
// 多行 Raw String Literal
// 可以直接保留換行與縮排
string multiLine = """
"Hello World!" is typically the first program someone writes.
""";
// Raw String Literal 很適合寫 XML / JSON / HTML
// 不需要處理 \" 或 \n
string embeddedXML = """
<element attr = "content">
<body style="normal">
Here is the main text
</body>
<footer>
Excerpts from "An amazing story"
</footer>
</element >
""";
// 編譯器會自動移除共同縮排
// 讓字串內容保持整齊
// 如果字串內本身包含 """
// 可以增加外層雙引號數量
string rawStringLiteralDelimiter = """"
Raw string literals are delimited
by a string of at least three double quotes,
like this: """
"""";****
字串建立後,內容不能被直接修改。
舉例來說:
string text = "Hello";
text += " World";
表面上看起來像是把"World"加到原本的"Hello"後面,但實際上不是修改原本的字串,而是建立新的字串 "Hello World",讓text指向新的字串,原本"Hello"仍然存在(之後可能被垃圾回收(GC))
也就是說,字串變數改變時,通常是「重新建立新字串」,不是修改舊字串本身。
字串不變性代表字串內容在建立後無法被直接修改。當程式看起來像是在「改變」字串時,實際上通常是建立了一個新的字串物件。這種特性能提升安全性、穩定性與記憶體共享效率,但在大量字串操作時也可能造成額外效能負擔,因此需要依情況選擇適合的字串處理方式。
using System.Globalization;
// =========================
// 字串格式化(String Formatting)
// =========================
// 標題列
Console.WriteLine(" Name Age Score ");
Console.WriteLine("============ ==== ========");
// 建立測試資料
var name = "Tom";
var age = 47;
var score = 88.555;
// 基本插值字串(未對齊)
// Console.WriteLine($"{name} {age} {score}");
// 欄位寬度格式化
// {變數,欄位寬度}
// 正數 = 靠右對齊
Console.WriteLine($"{name,12} {age,4} {score,8}");
// 負數 = 靠左對齊
// 0000 = 不足補 0
// N1 = 數字格式,小數點 1 位
Console.WriteLine($"{name,-12} {age,4:0000} {score,8:N1}");
Console.WriteLine();
// =========================
// 數值格式化(Numeric Formatting)
// =========================
// 欄位寬度 4 格,預設靠右
Console.WriteLine("{0,4}", score);
// N2 = Number 格式,小數點 2 位
// 結果:88.56
Console.WriteLine($"{score:N2}");
// C2 = Currency 貨幣格式,小數點 2 位
// 會依系統文化顯示貨幣符號
Console.WriteLine($"{score:C2}");
// E = 科學記號(Exponential)
// 結果類似:8.855500E+001
Console.WriteLine($"{score:E}");
// X = 十六進位格式(Hexadecimal)
// 注意:只支援整數,所以先轉 int
Console.WriteLine($"0x{(int)score:X}");
Console.WriteLine();
// =========================
// 日期與時間格式化(DateTime Formatting)
// =========================
// 現在時間
DateTime dt1 = DateTime.Now;
// 指定日期
DateTime dt2 = new DateTime(2025, 6, 28);
// 指定日期 + 時間 + 毫秒
DateTime dt3 = new DateTime(2025, 6, 28, 11, 57, 30, 000);
// d = 短日期格式
Console.WriteLine("{0:d}", dt1);
// D = 完整日期格式
Console.WriteLine("{0:D}", dt1);
// r = RFC1123 格式(網路常用)
Console.WriteLine("{0:r}", dt1);
// s = ISO 8601 格式
Console.WriteLine("{0:s}", dt1);
// 自訂格式:年-月-日
Console.WriteLine("{0:yyyy-MM-dd}", dt1);
// 自訂格式:年月日 + 時分秒毫秒
// hh = 12 小時制
// HH = 24 小時制
// fff = 毫秒
Console.WriteLine("{0:yyyy-MM-dd:hh:mm:ss:fff}", dt1);
// MMM = 英文月份縮寫
// 例如:Jun
Console.WriteLine("{0:yyyy-MMM-dd:hh:mm:ss:fff}", dt1);
// 時間格式
Console.WriteLine("{0:hh:mm:ss}", dt1);
// ddd = 星期縮寫
// 依系統文化不同可能顯示不同語言
Console.WriteLine("{0:ddd}", dt1);
Console.WriteLine();
// =========================
// CultureInfo 文化格式
// =========================
// 指定英文(美國)文化
var culture = new CultureInfo("en-US");
// 英文星期縮寫
// 例如:Sat
Console.WriteLine(dt1.ToString("ddd", culture));
// 英文完整星期
// 例如:Saturday
Console.WriteLine(dt1.ToString("dddd", culture));
// =========================
// 字串操作(String Operations)
// =========================
// 建立字串
var s1 = "Robert";
var s2 = "John";
// 字串串接
// 使用 + 將字串組合
var s3 = s1 + " " + s2;
// 不同型別與字串串接時
// 會自動轉成字串
var s4 = s1 + 1 + false + 2.5;
// 輸出結果
Console.WriteLine(s3);
Console.WriteLine(s4);
Console.WriteLine();
// =========================
// 字串大小寫轉換
// =========================
// 轉小寫
Console.WriteLine(s1.ToLower());
// 轉大寫
Console.WriteLine(s1.ToUpper());
// \t = Tab 空白縮排
Console.WriteLine($"{s1}\t{s2}");
// \n = 換行
Console.WriteLine($"{s1}\n{s2}");
// \\ = 顯示反斜線 \
Console.WriteLine($"{s1}\\{s2}");
Console.WriteLine();
// =========================
// 字串索引與切割
// =========================
var robert = "Robert";
// 使用索引存取字元
// 字串索引從 0 開始
// Robert
// 012345
Console.WriteLine("the 3rd character of Robert is: {0}", s1[3]);
// Substring(startIndex, length)
// 從索引 1 開始,取 3 個字元
// 結果:obe
Console.WriteLine(robert.Substring(1,3));
// Substring(startIndex)
// 從索引 3 開始取到最後
// 結果:ert
Console.WriteLine(robert.Substring(3));
Console.WriteLine();
// =========================
// Split 字串切割
// =========================
// 建立包含逗號的字串
var s5 = "Marry, Terrice";
// 使用逗號切割
// 注意:第二個元素前面會保留空白
var s6 = s5.Split(',');
// 顯示切割結果
Console.WriteLine($"'{s6[0]}'");
Console.WriteLine($"'{s6[1]}'");
Console.WriteLine();
// =========================
// Split + TrimEntries
// =========================
// TrimEntries 會自動移除前後空白
var s7 = s5.Split(',', StringSplitOptions.TrimEntries);
// 顯示去除空白後的結果
Console.WriteLine($"'{s7[0]}'");
Console.WriteLine($"'{s7[1]}'");
Console.WriteLine();
// =========================
// String.Join 字串合併
// =========================
// 建立字串陣列
var people = new string[] {"Robert", "John", "Marry"};
// 使用逗號合併
Console.WriteLine("We have people: {0}", String.Join(',', people));
Console.WriteLine();
// 使用 ", " 合併
// 會更容易閱讀
Console.WriteLine("We have people: {0}", String.Join(", ", people));
Console.WriteLine();
// =========================
// 補充
// =========================
// 建議查詢:
// google: c# string class
//
// 常用功能:
// - Contains
// - Replace
// - StartsWith
// - EndsWith
// - IndexOf
// - Trim
// - Insert
// - Remove
// - Format
字串處理是程式開發的基本功。雖然功能繁多,但不需要硬背,重點是知道C#有提供這些便利的工具(特別是強大的字串插值與 C# 11 的原始字串)。