首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 字元大小寫轉換:從 ASCII 位運算到 Unicode 正規化的完整指南

     編輯:關於C語言

前言

字元大小寫轉換看似簡單,實則涉及 ASCII 碼結構、Unicode 字元屬性、文化特定規則 (土耳其語 I/ı)、正規化形式等深層議題。本文從面試經典題目切入,層層深入至生產級最佳實務。

一、經典面試解法:ASCII 位運算


// 僅適用 ASCII A-Z / a-z
public static string SwapCaseAscii(string input)
{
    char[] arr = input.ToCharArray();
    for (int i = 0; i < arr.Length; i++)
    {
        char c = arr[i];
        if (c >= 'A' && c <= 'Z') arr[i] = (char)(c | 0x20);      // 大寫→小寫:設定 bit 5
        else if (c >= 'a' && c <= 'z') arr[i] = (char)(c & ~0x20); // 小寫→大寫:清除 bit 5
    }
    return new string(arr);
}
  • 原理:ASCII 大小寫差異僅在第 5 位 (0x20 = 32)。'A' (0x41) | 0x20 = 'a' (0x61)。
  • 優點:無分支預測失誤、極快、無分配 (陣列複用)。
  • 缺點:僅限 ASCII 英文字母,非英文、全形、重音字元全部失效。

二、.NET 內建方法:char.ToUpper/ToLower 與 string.ToUpper/ToLower


// 當前文化特性 (CurrentCulture) - 可能受系統語言影響
string upper = input.ToUpper();          // 等同 ToUpper(CultureInfo.CurrentCulture)
string lower = input.ToLower();

// 不變文化特性 (InvariantCulture) - 固定規則,適合檔案路徑、XML 標籤、程式識別碼
string upperInv = input.ToUpperInvariant(); // 等同 ToUpper(CultureInfo.InvariantCulture)

// 字元層級
char upperChar = char.ToUpper(c, CultureInfo.InvariantCulture);

關鍵差異:

場景推薦原因
使用者介面顯示CurrentCulture尊重使用者語言習慣
檔案路徑、註冊表鍵、XML/JSON 鍵名、程式內部識別碼InvariantCulture跨機器、跨語言結果一致
安全性比較 (密碼、Token)OrdinalIgnoreCase不做語言學轉換,純位元組比較

三、Unicode 複雜性:超越 Basic Latin

1. 擴展拉丁字母


// 德語 ß (U+00DF) 大寫為 "SS" (兩個字元)
"straße".ToUpperInvariant() // "STRASSE" 長度變長!

// 希臘語 Sigma 有兩種小寫形式
"Σ".ToLowerInvariant() // "σ" (詞中) 或 "ς" (詞尾) - 需語境

2. 土耳其語 I 問題


// 土耳其語 (tr-TR) 有四個 I
// 大寫:I (U+0049) 、İ (U+0130)
// 小寫:ı (U+0131) 、i (U+0069)

var tr = new CultureInfo("tr-TR");
"I".ToLower(tr)      // "ı" (點失落)
"İ".ToLower(tr)      // "i" (保留點)
"ı".ToUpper(tr)      // "I"
"i".ToUpper(tr)      // "İ"

// 使用 InvariantCulture 避免驚喜
"I".ToLowerInvariant() // "i"

教訓:任何涉及系統識別碼、快取鍵、路徑的大小寫轉換,**必須指定 CultureInfo.InvariantCulture**。

四、字串比較:別用 ToUpper/ToLower


// 錯誤:分配新字串、文化特性陷阱、效能差
if (a.ToUpper() == b.ToUpper()) ...

// 正確:OrdinalIgnoreCase - 直接比較碼位,忽略大小寫 (僅 ASCII 範圍)
if (string.Equals(a, b, StringComparison.OrdinalIgnoreCase)) ...

// 正確:CurrentCultureIgnoreCase - 語言學比較 (較慢)
if (string.Equals(a, b, StringComparison.CurrentCultureIgnoreCase)) ...

五、高效能大小寫轉換:StringBuilder + Span


// 避免多次字串連接分配
public static string SwapCaseFast(string input)
{
    var sb = new StringBuilder(input.Length);
    foreach (char c in input)
    {
        if (char.IsUpper(c)) sb.Append(char.ToLowerInvariant(c));
        else if (char.IsLower(c)) sb.Append(char.ToUpperInvariant(c));
        else sb.Append(c);
    }
    return sb.ToString();
}

// .NET 6+ Span 版本 (零分配,就地轉換)
public static void SwapCaseInPlace(Span<char> buffer)
{
    for (int i = 0; i < buffer.Length; i++)
    {
        char c = buffer[i];
        if (char.IsUpper(c)) buffer[i] = char.ToLowerInvariant(c);
        else if (char.IsLower(c)) buffer[i] = char.ToUpperInvariant(c);
    }
}

六、正規化與大小寫:ToUpperInvariant vs ToUpper + Normalize


// 組合字元 (如 é = e + ́)
string composed = "é";           // U+00E9 (NFC)
string decomposed = "e\u0301";    // U+0065 U+0301 (NFD)

composed.ToUpperInvariant()     // "É" (U+00C9)
decomposed.ToUpperInvariant()   // "É" (U+0045 U+0301) - 仍為分解形式

// 最佳實務:先正規化再轉換
string NormalizeAndUpper(string s) => s.Normalize(NormalizationForm.FormC).ToUpperInvariant();

七、總結:決策樹

  1. 僅處理 ASCII 英文、極致效能 → 位運算 c ^ 0x20 (確認輸入範圍)。
  2. 一般應用、使用者可見字串 → ToUpper(CurrentCulture) / ToLower(CurrentCulture)。
  3. 系統內部識別碼、路徑、鍵值、協定欄位 → ToUpperInvariant() / ToLowerInvariant()。
  4. 字串比較 → string.Equals(a, b, StringComparison.OrdinalIgnoreCase) (系統) 或 CurrentCultureIgnoreCase (語言)。
  5. 大量資料處理 → StringBuilder 或 Span<char> 就地修改。
  6. 國際化支援 → 測試土耳其語、德語、希臘語、車臣語等邊界案例。

結語

大小寫轉換是「簡單問題、複雜答案」的經典案例。理解 ASCII 位運算固然展現底層功力,但在 Unicode 時代,正確使用 CultureInfo.InvariantCulture、StringComparison.OrdinalIgnoreCase、NormalizationForm 才是專業開發者的分水嶺。下次面試若再遇到這題,不妨先問:「這個系統的目標語言與用途是什麼?」

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved