PowerShellのUnicode正規化NFKCで全角英数字を揃える ― 元データを壊さない方法

PowerShellカテゴリを表すパンダのイラスト PowerShell

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。.NETのString.NormalizeとNormalizationForm.FormKCの公式仕様を照合し、PowerShellからUnicode正規化を観察するサンプルを作成しました。PowerShell実機での実行確認は未実施です。

検証ステータス:📘 .NET公式仕様確認済み/PowerShell実機未確認

ExcelやCSVで「ABC123」と「ABC123」が混在すると、見た目はほぼ同じなのに別の値として比較されることがあります。半角カタカナや丸数字が混ざった場合も同様です。

.NETのString.NormalizeでNormalizationForm.FormKCを指定すると、Unicodeの互換正規化(NFKC)で多くの表記差を統一できます。ただし、NFKCには元の表記を復元できない変換もあるため、商品コード・社員ID・パスワードなどに無条件で適用してはいけません。

PowerShellで最小例を試す

PowerShell 7やWindows PowerShell 5.1など、.NETのString.Normalizeを使える環境を想定します。

$before = 'ABC123'
$after  = $before.Normalize([Text.NormalizationForm]::FormKC)

"Before: $before"
"After : $after"

期待される表示は次のとおりです。これは公式仕様から予想した結果であり、実機出力ではありません。

Before: ABC123
After : ABC123

FormKCは、互換分解と正準合成を行うNFKC正規化です。よく似たFormC(NFC)は主に正準等価を扱い、互換文字の統一とは用途が異なります。

いろいろな文字を比較する

次のサンプルでは変換前後を表にして、実際に内容が変わったか確認します。入力はダミー文字列のみで、ファイルやレジストリには書き込みません。

$values = @(
    'ABC123'
    'カタカナ'
    '① Ⅳ'
)

$results = foreach ($original in $values) {
    $normalized = $original.Normalize([Text.NormalizationForm]::FormKC)

    [pscustomobject]@{
        Before  = $original
        After   = $normalized
        Changed = ($original -cne $normalized)
    }
}

$results | Format-Table -AutoSize

予想される変換は、ABC123→ABC123、カタカナ→カタカナ、① Ⅳ→1 IVです。丸数字やローマ数字の表記が変わることからも、単なるスペース削除や英数字の幅変更ではないと分かります。

同じコードはDaily-Code-SamplesのNFKC実験に保存しています。サンプルは読み取りと表示だけで、CSVを勝手に上書きしません。

1か所変更してNFCと比べる

FormKCをFormCに変えて同じ文字を比較します。

$text = 'ABC123'
$text.Normalize([Text.NormalizationForm]::FormC)
$text.Normalize([Text.NormalizationForm]::FormKC)

FormCでは全角英数字がそのままで、FormKCでは半角英数字へ統一されることが期待されます。どちらが「正解」というより、何を同じ文字として扱いたいかで選ぶものです。

.NET公式のString.NormalizeとNormalizationFormには正規化形式の説明があります。

仕事で使うなら「正規化前」を残す

例えば販売データの品名欄に、入力者によって全角と半角が混ざる場合、検索や集計のために正規化した別の列を追加すると便利です。

$rows = @(
    [pscustomobject]@{ Item = 'ABC123'; Count = 2 }
    [pscustomobject]@{ Item = 'ABC123';   Count = 3 }
)

$rows | Select-Object Item, Count, @{
    Name = 'SearchKey'
    Expression = {
        $_.Item.Normalize([Text.NormalizationForm]::FormKC)
    }
}

ここでは元のItemを保持し、新しいSearchKeyを追加しています。元データを失わないため、後から「同じ文字列として扱ってよいか」を確認できます。

注意: 異なる元の文字列が同じSearchKeyになることがあります。そのため、社員番号や商品コードで一意性を保証するなら、正規化後に重複が発生するか確認してからキーとして採用します。

誤って統一してはいけない例

データNFKC適用の考え方
検索補助用の品名元の文字列と別列で正規化を試せる
入力された全角英数字の説明文用途によっては統一が便利
商品コード・管理番号正規化で別IDが衝突しないか検証が必要
パスワード・署名対象意味や照合結果が変わるため勝手に変更しない
ファイル名既存のパスとの不一致や衝突を確認

また、Unicode正規化は「似て見えるすべての文字」を同一化するものではありません。異なる文字体系の見た目が似た文字や、不可視文字、末尾空白などをすべて解決する万能な処理ではありません。

失敗・境界条件

入力が$nullの場合、文字列メソッドをそのまま呼ぶと失敗します。CSVやAPIから受け取るデータでは、最初にnullかどうかを確認してください。

function ConvertTo-Nfkc([AllowNull()][string]$Value) {
    if ($null -eq $Value) { return $null }
    return $Value.Normalize([Text.NormalizationForm]::FormKC)
}

Unicodeの正規化に失敗する不正な文字列についても、業務で利用する場合には例外処理を検討します。さらにPowerShellの-eqなどの比較演算子は既定で大文字・小文字を区別しないため、ケースまで厳格に判定したい場合は-ceqや-cneを使います。

公式資料

文書情報

記事タイトル
PowerShellのUnicode正規化NFKCで全角英数字を揃える ― 元データを壊さない方法
作成日
更新日
Source URL
https://papanda925.com/?p=18091

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました