PowerShellでGrapheme Clusterについて処理を考える

2025-06-01 PowerShellでGrapheme Cluster

🔍 Grapheme Cluster(書記素クラスタ)とは?

Grapheme Cluster(グラフェムクラスタ)とは、ユーザーが「1文字」として認識するユニコードの文字単位のことです。

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で表示する方法【コード付き解説】

MenuFlyoutWinUI 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について処理を考える