サロゲートペアを扱うシステムでは、Rune を使おう
サロゲートペアを扱うシステムでは、Rune
を使おう
はじめに
絵文字や異体字セレクタ(IVS)などを扱うシステムでは、「1文字 = 1 char
」 という前提がすぐに崩れます。
.NET の string
は内部的に UTF-16 を採用しているため、Unicode の一部文字は サロゲートペア(2つの char
の組み合わせ)で表現されるからです。
その結果、string.Length
や s[0]
といった処理は「文字数」ではなく「UTF-16 のコードユニット数」になり、絵文字などを正しく1文字として扱えません。
サロゲートペアとは?
Unicode では U+10000 以上のコードポイントを表す際、16bit 1文字では収まらないため、
上位サロゲート+下位サロゲートの2つの char
を1文字として扱います。
例:
1 | string s = "𩸽"; // U+29E3D |
この例では、魚の絵文字「𩸽」(U+29E3D)がサロゲートペアで表現されているため、
見た目は1文字でも Length は2。
Substring などで途中を切り出すと、サロゲートペアが分断されて文字化けする恐れがあります。
.NET の解決策:System.Text.Rune
.NET Core 3.0 以降(.NET 5 以降を含む)では、System.Text.Rune が用意されています。
Rune は Unicode スカラ値 = 1文字 を表す構造体で、サロゲートペアもまとめて1単位として扱えます。
基本例
1 | using System.Text; |
出力:
1 | U+29E3D 𩸽 |
EnumerateRunes() はサロゲートペアを自動的に認識し、
正しい Unicode スカラ値を1つずつ返します。
Rune を使うメリット
- 文字化け防止
- サロゲートペアを分断せず「1文字単位」で安全に処理できる。
- IVSや絵文字にも対応
- 異体字セレクタや絵文字など、特殊コードポイントも正しく扱える。
- 既存の string と共存可能
- 既存APIはそのまま使いながら、文字操作だけを Rune ベースに置き換えられる。
実用ユーティリティの例
Rune を活用した便利メソッドをまとめておくと、レガシーコードの置き換えが容易になります。
1 | public static class UnicodeHelper |
これで 「Rune 単位の Length」 や 「Rune 単位の Substring」 を簡単に呼び出せます。
まとめ
UTF-16 では「1文字 = 1 char」は成り立たず、サロゲートペアやIVSを安全に扱う必要がある。
.NET では System.Text.Rune がその課題を解決する最適な手段。
段階的に Rune ベースへ移行することで、レガシーシステムでも国際化・絵文字対応を堅牢に実装できる。
ポイント: 「文字」を安全に扱うには Rune を使う。
サロゲートペアや絵文字対応が必要なシステムでは、今こそ Rune への移行を検討しましょう。