PowerShellでGrapheme Clusterについて処理を考える
2025-06-01
🔍 Grapheme Cluster(書記素クラスタ)とは?
Grapheme Cluster(グラフェムクラスタ)とは、ユーザーが「1文字」として認識するユニコードの文字単位のことです。
éは1文字に見えて、実際はe+ 合成アクセント(U+0301)🇯🇵(国旗)は2つの地域コード文字(U+1F1EF U+1F1F5)から構成される
PowerShell の -split や .Length、.Substring() などの文字列操作は 「コード単位」や「コードポイント単位」で動作します。つまり「見た目の1文字」がバラバラに扱われる可能性があります。
.Length の罠
$text = "é"
$text.Length
出力結果は 2 になる場合がありますé が e と合成アクセントの2つのコードポイントからなるためです。
🧨 PowerShellでの罠:「e`u0301」はエラーになる
PowerShellでは次のような書き方は ParserError を引き起こします:
$text = "e`u0301" # ❌ パースエラー:Unicode escape sequence is not valid
✅ 正しい書き方
$text = 'e' + [char]0x0301 # e + 合成アクセント
💡 Grapheme Cluster 単位での文字数取得方法
System.Globalization.StringInfo クラスを使えば、見た目上の「1文字」を正確に扱えます。
Add-Type -AssemblyName "System.Globalization"
$text = 'e' + [char]0x0301 + 'あ'
$si = New-Object System.Globalization.StringInfo $text
$si.LengthInTextElements # → 2
🔄 Grapheme Cluster 単位での分割
$text = 'e' + [char]0x0301 + 'あ'
$elements = [System.Globalization.StringInfo]::GetTextElementEnumerator($text)
while ($elements.MoveNext()) {
$elements.Current
}
出力結果:
é
あ
🔧 実用関数①:先頭のGraphemeだけ取得する
function Get-FirstGrapheme {
param([string]$text)
$enum = [System.Globalization.StringInfo]::GetTextElementEnumerator($text)
if ($enum.MoveNext()) { return $enum.Current }
return ""
}
✂️ 実用関数②:Grapheme単位で文字列を切り詰める
function Truncate-Grapheme {
param(
[string]$text,
[int]$maxLength
)
$result = ""
$count = 0
$enum = [System.Globalization.StringInfo]::GetTextElementEnumerator($text)
while ($enum.MoveNext() -and $count -lt $maxLength) {
$result += $enum.Current
$count++
}
return $result
}
# 使用例
Truncate-Grapheme ("👩" + [char]0x200D + "🚀" + "宇宙飛行士") 3
🛡️ まとめ:Grapheme Cluster 対応の重要性と対策
| 問題 | 対応方法 |
|---|---|
| .Length が実際と異なる | StringInfo.LengthInTextElements を使用 |
| Substring() で文字化け | GetTextElementEnumerator() で分割処理 |
| "e`u0301" でパースエラー | 'e' + [char]0x0301 で生成 |
| 絵文字・国旗が分割される | Grapheme 単位で列挙して処理 |
📌 結論
PowerShell で Unicode を扱う際、「見た目の1文字 ≠ コード単位の1文字」であることを理解し、System.Globalization.StringInfo を活用することで、Grapheme Cluster を正確に処理できます。
これにより、国際化対応(i18n)、絵文字など表示の安定性が大きく向上します。
WinUI 3 / XAML の Grid.Width 設定方法
WinUI 3でMenuFlyoutをShowAtで表示する方法【コード付き解説】
MenuFlyout は WinUI 3 で便利なポップアップメニュー
WinUI 3の開発で混乱しがちな「空白のウィンドウ」と「空白のページ」の違い
PowerShellでMSIXアプリ(Storeアプリ)を起動する方法|AppUserModelIdとURIスキーム活用術
Microsoft Storeアプリ更新時のロールアウト設定まとめ
PowerShellでgrepのような文字列検索を実現する方法【UTF-8・Shift-JIS対応・サブフォルダ対応】
PowerShellでtail -f!WindowsでUTF-8対応のリアルタイムログ監視を実現する方法
Microsoft純正の新しいコンソールエディタ「edit」が復活!| edit.exe インストール方法
Microsoft Authenticatorのオートフィル機能が2025年7月に終了
RuntimeBroker.exeとMsEdgeWebView2.exeとは?Windows 11のプロセスについて
PowerShellでGrapheme Clusterについて処理を考える
【C#】大容量ファイルを指定サイズ以下に分割する方法|.NET8対応コード付き
【C# .NET 8】ファイルから重複行を削除する2つの方法|Distinct vs HashSet
git switchの使い方とgit checkoutとの違い
Windows 11でタスクマネージャー以外からアプリを終了させる方法【PowerShell・コマンドプロンプト】