## 關於 C# `Trim()` 方法修剪空白字元 最近在做後端開發時遇到字串處理的問題,發現從 DB 取出的 Unicode 字元除了空白字元外,還包含一個空白字元,它的編碼是`U+00A0`,即不換行空格(Non-breaking space)。 寫了幾段的簡單程式碼用 `Trim()` 測試,發現這個 `Trim()` 方法不只能移除我們一般常見的空白字元,而是有一組支援被修剪的字元,於是就寫了這篇文章來探討 C# `Trim()` 方法的特性。 ### Unicode 空白字元的定義 Unicode 標準定義了許多空白字元,用於排版和格式化文本。這些空白字元包括常見的空格和製表符,以及一些特殊的空白字元,一般而言我們最常看到的是(`U+0020`),即普通半形空格。 但除此之外也會遇到(`U+00A0`),即不換行空格(Non-breaking space),這是一種特殊的空白字元,用於防止文字在該位置換行。 在 Thai (泰文) 與 Myanmar (緬甸文) 語系等部分[南亞語系](https://www.unicode.org/versions/Unicode16.0.0/core-spec/chapter-16/)中,預設輸入空白會用 `U+200B` 這個字元做文字間格,這是他們鍵盤的預設配置。 而這在 HTML 中也是常見的,用` `來表示,至於其他空白字元則有興趣可以翻找 [Unicode 官網](https://home.unicode.org/) ,此處不多贅述。 ### C# `Trim()` 方法的定義 在 C# 中,當 `Trim(Char[])` 方法主要用來移除字串開頭與結尾的指定字元,而當沒有參數時,它的主要功能是移除字串開頭和結尾的空白字元。 這些空白字元是符合 Unicode 標準中定義的,即當傳遞給 `Char.IsWhiteSpace` 方法時返回 `true` 的字元[^1][^2]。 ### 早期版本的行為差異 在 .NET Framework 3.5 SP1 及更早版本中, `Trim()` 方法使用自行維護的空白字元列表進行修剪,這導致以下結果: - 會修剪以下字元 - [ZERO WIDTH SPACE (`U+200B`)](https://www.fileformat.info/info/unicode/char/200B/index.htm) - [ZERO WIDTH NO-BREAK SPACE (`U+FEFF`)](https://www.fileformat.info/info/unicode/char/FEFF/index.htm) - 不修剪以下三個字元: - MONGOLIAN VOWEL SEPARATOR (`U+180E`) - NARROW NO-BREAK SPACE (`U+202F`) - MEDIUM MATHEMATICAL SPACE (`U+205F`) ### 目前版本 `Trim()` 的行為 自 .NET Framework 4 起, `Trim()` 方法修剪的範圍擴展至所有 Unicode 空白字元,即跟著 Unicode 的標準來定義空白字元,這導致上述提及的 ZERO WIDTH SPACE (`U+200B`)與 ZERO WIDTH NO-BREAK SPACE (`U+FEFF`)不再被修剪。 這是官方英文原文的說法,但實際上這個說法有些瑕疵,其實應該是微軟從Unicode規範中挑自己想拿來用的分類來作為Trim的預設字元集合。 實際定義為: `Trim()` 方法會移除所有符合 **傳遞給 `Char.IsWhiteSpace` 方法時返回 `true` 的字元**,包含以下四項[^1]: - UnicodeCategory.SpaceSeparator (Zs) - UnicodeCategory.LineSeparator (Zl) - UnicodeCategory.ParagraphSeparator (Zp) - 其他項目: - CHARACTER TABULATION (U+0009) - LINE FEED (U+000A) - LINE TABULATION (U+000B) - FORM FEED (U+000C) - CARRIAGE RETURN (U+000D) - NEXT LINE (U+0085) ### 結論 使用 `Trim()` 的時候到底需不需要注意上述內容呢? 大多數情況是不需要的,大多數的空白字元就是最常見的`U+00A0`,偶爾可能會跟我一樣遇到`U+00A0`(Non-breaking space),但這些都可以安心的「Trim 它(?)」。 但如果遇到奇怪的編碼,還是建議去看看有那些字元是不是有被支援,如果沒有,則可能要自行寫一個方法來處理。 [^1]: **IsWhiteSpace(Char)** https://learn.microsoft.com/en-us/dotnet/api/system.char.iswhitespace?view=net-9.0#system-char-iswhitespace(system-char) [^2]: **Trim()** https://learn.microsoft.com/en-us/dotnet/api/system.string.trim?view=net-9.0#system-string-trim