Ruby でローマ数字の文字 (機種依存文字) をアルファベットに変換する


やりたいこと

例えば (U+2166) を VII に変換したい。

方法

愚直な方法

def replace_roman_numerals_with_alphabets(str)
  conversions = {
    'Ⅰ' => 'I', 'Ⅱ' => 'II', 'Ⅲ' => 'III', 'Ⅳ' => 'IV', 'Ⅴ' => 'V',
    'Ⅵ' => 'VI', 'Ⅶ' => 'VII', 'Ⅷ' => 'VIII', 'Ⅸ' => 'IX', 'Ⅹ' => 'X',
    'Ⅺ' => 'XI', 'Ⅻ' => 'XII'
  }.freeze

  str.gsub(/[#{conversions.keys}]/, conversions)
end

replace_roman_numerals_with_alphabets('ファイナルファンタジーⅦ')
#=> "ファイナルファンタジーVII"

変換ルールを自分で用意するのは大変

スマートな方法

def replace_roman_numerals_with_alphabets(str)
  # Unicode の U+2160 から U+217F までがローマ数字。
  roman_numerals_pattern = /[\u2160-\u217F]/ 
  str.gsub(roman_numerals_pattern) { |char| char.unicode_normalize(:nfkd) }
end

replace_roman_numerals_with_alphabets('ファイナルファンタジーⅦ')
#=> "ファイナルファンタジーVII"

# ちなみに……
'ファイナルファンタジーⅦ'.unicode_normalize(:nfkd)
#=> "ファイナルファンタジーVII"

NFKD 形式 (あるいは NFKC 形式) で Unicode 正規化 することで、対応するアルファベットに分解することができる。

参考