C#のstring.Trim()は全角スペースまで削って下さりやがる

C#のstringクラスにあるTrim()メソッドは、C#の三大便利関数の1つと言って良いくらい便利な関数だ。

言わずもがな、文字列の先頭と末尾に付随する空白を削除してくれる関数であるが、空白って一体なんなのよというと「Unicodeが定める空白文字」である。従って、Trim()は文字列の前後からUnicodeが定める空白文字を削除する関数という事になる。(更に言うと.NET Frameworkのバージョンによって細部の挙動が違う。詳細はMSDNを参照の事。)

んじゃんじゃUnicodeの空白文字ってなんぞ?というと、C#的にはChar.IsWhiteSpace(letter) == trueとなる文字である。詳細はUnicodeの規格書なりWikipediaなりを見て頂くとして、true判定になる文字には半角スペース(U+0020)やタブ文字(U+0009)は然ることながら、全角スペース(U+3000)も含まれるのだ。つまりTrim()を使うと全角スペースも奇麗さっぱりなくなっちゃう。なんというか、C/C++の非WIDE文字な文字列操作に慣れている身からすると、直感とは異なる挙動なわけ。

今回はこれにハマった。削られちゃマズい全角スペースが見事になくなってて、Trim()の挙動を初めて知ったという(´・ω・`)

回避策は引数ありバージョンのTrim()で、全角スペースを除いた空白文字配列を渡すしかない模様。↓こんな感じで拡張メソッド化しておくと便利に使えるよ(`・ω・´)

public static class MyStringAdditions
{
    static char[] WhiteSpaceDelimiters = new char[] {
        '\u0009',  // CHARACTER TABULATION
        '\u000A',  // LINE FEED
        '\u000B',  // LINE TABULATION
        '\u000C',  // FORM FEED
        '\u000D',  // CARRIAGE RETURN
        '\u0020',  // SPACE
        '\u00A0',  // NO-BREAK SPACE
        '\u2000',  // EN QUAD
        '\u2001',  // EM QUAD
        '\u2002',  // EN SPACE
        '\u2003',  // EM SPACE
        '\u2004',  // THREE-PER-EM SPACE
        '\u2005',  // FOUR-PER-EM SPACE
        '\u2006',  // SIX-PER-EM SPACE
        '\u2007',  // FIGURE SPACE
        '\u2008',  // PUNCTUATION SPACE
        '\u2009',  // THIN SPACE
        '\u200A',  // HAIR SPACE
        '\u200B',  // ZERO WIDTH SPACE
//      '\u3000',  // IDEOGRAPHIC SPACE -- これが所謂全角スペース
        '\uFEFF' // ZERO WIDTH NO-BREAK SPACE
    };
 
    public static string TrimWithoutZenkakuSpace(this string str)
    {
        string s = str.Trim(WhiteSpaceDelimiters);
        return s;
    }
}

この件とは直接関係ないけど、TrimStartTrimEndなんてメソッドもあったんだね。取り除きたい文字の配列を渡すと、対象文字列の先頭もしくは末尾から除去してくれる。Trimの分割バージョンみたいなやつ、というよりもTrimTrimStartTrimEndの合体技と言った方がいいか。覚えといて損は無さそう。

参考サイト