問い合わせフォームの「123-4567」を「123-4567」にそろえたいとき、C# なら次の1行がよく紹介されます。
string s = args[0].Normalize(NormalizationForm.FormKC);
このプログラムを Mac で動かすと、全角の英数字は半角になりました。ところが、毎朝の検証に使っている Linux のコンテナ(Docker)では、全角のまま、何も変わらずに出てきました。エラーも警告も出ません。
実際に出た答え
CODE Polyglot の入門 第9回 の正解表(7件)で動かした結果です(.NET 10.0.402)。
| 入力 | 正解 | Mac | Linux のコンテナ |
|---|---|---|---|
| 123-4567 | 123-4567 | 123-4567 | 123-4567 |
| ABC abc | ABC abc | ABC abc | ABC abc |
| Tel:03-1234-5678 | Tel:03-1234-5678 | Tel:03-1234-5678 | Tel: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回 にあります
- 第1回:「2026-02-30」を渡したら、PHP と JavaScript だけが黙って3月2日にした
- 第2回:JavaScript で「月の最終日」を出したら、日本では毎回1日前になった
- 第3回:C# の Normalize(FormKC) が、Docker の中では何もしなかった(この記事)
- 第4回:辞書の「取り出す順番」を10言語で20回ずつ試したら、5通りの性格に分かれた
Analyzegear

