C# の Normalize(FormKC) が、Docker の中では何もしなかった ― その書き方、本当に通る?③

C#
B!

問い合わせフォームの「123-4567」を「123-4567」にそろえたいとき、C# なら次の1行がよく紹介されます。

string s = args[0].Normalize(NormalizationForm.FormKC);

このプログラムを Mac で動かすと、全角の英数字は半角になりました。ところが、毎朝の検証に使っている Linux のコンテナ(Docker)では、全角のまま、何も変わらずに出てきました。エラーも警告も出ません。

実際に出た答え

CODE Polyglot の入門 第9回 の正解表(7件)で動かした結果です(.NET 10.0.402)。

入力正解MacLinux のコンテナ
123-4567123-4567123-4567123-4567
ABC abcABC abcABC abcABC abc
Tel:03-1234-5678Tel:03-1234-5678Tel:03-1234-5678Tel:03-1234-5678
合計7件中5件7件中3件

Mac で落ちた2件は、NFKC が「カナ」を「カナ」に、「①」を「1」に変えてしまうケースです(これは Python・JavaScript・Java・Kotlin・Ruby・Swift でも同じでした)。Linux では、何も変えないので、その2件は逆に通っています。

なぜ何もしないのか

コンテナには、環境変数 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 が設定されていました。.NET の「インバリアント モード」です。文字や言語の情報を持つライブラリ(ICU)を使わずに動くので、コンテナを小さくできます。小さな .NET のイメージではよく使われる設定です。

このモードでは、Normalize は全角の文字をそのまま返しました。IsNormalized(FormKC) も True(もう正規化されている)を返します。

$ dotnet run check.cs        # DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
123 True

設定を外すと、ICU が入っていないので、今度は起動の時点で止まりました。

どう直したか

この回で直したいのは「全角の英数字・記号と全角スペース」だけなので、NFKC を使わずに、文字の番号で直します。全角の「!」(U+FF01)〜「~」(U+FF5E)は、0xFEE0 を引くと半角になります。

foreach (char c in args[0])
{
    if (c >= '!' && c <= '~') sb.Append((char)(c - 0xFEE0));
    else if (c == ' ') sb.Append(' ');
    else sb.Append(c);
}

これなら、Mac でも Linux でも、ICU があってもなくても同じ答えになります。

まとめ

  • 同じ C# のコードでも、動かす環境の設定で、文字列の処理の結果が変わることがある。しかも黙って変わる
  • 手元(Mac・Windows)で通っても、Docker の中で同じ答えになるとは限らない。本番と同じ環境でテストを回す
  • 10言語の全プログラムは 入門 第9回 にあります
連載「その書き方、本当に通る?」(全4回)
  1. 第1回:「2026-02-30」を渡したら、PHP と JavaScript だけが黙って3月2日にした
  2. 第2回:JavaScript で「月の最終日」を出したら、日本では毎回1日前になった
  3. 第3回:C# の Normalize(FormKC) が、Docker の中では何もしなかった(この記事)
  4. 第4回:辞書の「取り出す順番」を10言語で20回ずつ試したら、5通りの性格に分かれた
B!
← 一覧へ戻る