Rustで全角英数字を半角にするにはunicode-normalizationを使うとよさそう

Rustにおいて全角英数字を半角英数字に変換するのにはUnicode正規化を使うとよさそうです。
Unicode正規化が提供されているライブラリは複数存在するようですが、今回はunicode_normalizationクレートを利用することにしました。
以下にサンプルコードをまとめます。

Unicode正規化について

Unicode正規化は文字列の並びを統一的な表現に変換する手法の一つとなっているようです。

Unicode正規化には4種類あり、unicode.orgに規格が説明されています。

Wikipediaの説明を借りると、正則化の4種類は以下のようになっているようです。

  • NFD (Normalization Form Canonical Decomposition)
    • 正規化形式D
    • 文字は正準等価性によって分解される。
  • NFC (Normalization Form Canonical Composition)
    • 正規化形式C
    • 文字は正準等価性によって分解され、再度合成される。結果として文字の並びが変換前と変わることもありうる。
  • NFKD (Normalization Form Compatibility Decomposition)
    • 正規化形式KD
    • 文字は互換等価性によって分解される。
  • NFKC (Normalization Form Compatibility Composition)
    • 正規化形式KC
    • 文字は互換等価性によって分解され、正準等価性によって再度合成される。

正直分からないところも多いので、実際に試して確認してみます。

unicode-normalizationクレートを用いたサンプル

クレートをcargo add unicode-normalizationなどで追加しておきます。

以下がUnicode正規化のテストコードになります。

全半角の日本語と英数字を文字列に与えて正規化関数4種を適用しています。

use unicode_normalization::UnicodeNormalization;

fn main() {
    let str = "あいウエオカキクケコ漢字123ABC123ABC";

    println!("src:    {}", str);
    println!("nfd():  {}", str.nfd().collect::<String>());
    println!("nfc():  {}", str.nfc().collect::<String>());
    println!("nfkd(): {}", str.nfkd().collect::<String>());
    println!("nfkc(): {}", str.nfkc().collect::<String>());
}

以下が出力です。

src:    あいウエオカキクケコ漢字123ABC123ABC
nfd():  あいウエオカキクケコ漢字123ABC123ABC
nfc():  あいウエオカキクケコ漢字123ABC123ABC
nfkd(): あいウエオカキクケコ漢字123ABC123ABC
nfkc(): あいウエオカキクケコ漢字123ABC123ABC

少なくとも正準等価性の変換であるnfd(),nfc()では日本語全半角には影響がないようです。

互換等価性の変換であるnfkd(),nfkc()では半角カナが全角カナに、全角英数字が半角英数字に統一されています。

この2種の違いをみるとnfkd()が互換等価性による分解のみであり、nfkc()はその後に正準等価性による再合成が追加されているようです。

ただ、今回の日本語全半角の表記ブレを統一する目的であればどちらの利用でもよさそうです。

まとめ

  • Rustの全半角英数字の表記ブレを統一するにはUnicode正規化を行うとよい
  • unicode_normalizationクレートで提供されている
  • 日本語全半角に対してはnfkd(),nfkc()のどちらかを使うとよさそう