今年に入ってから本格的に副業を開始している。

自分ではなかなか書かないコードを書く機会が増えて喜ばしい一方、趣味のコードを書く時間が減っているのでブログのネタも少し落ち着いてきている。 今回はいわゆる小ネタではあるが、興味深いので残しておくことにした。

まずは次の文字列を比較してほしい。

アンデッドアンラック
アンデッドアンラック

CSVのデータを書き直し、テーブル上のデータを眺めていると不思議な文字列を発見した。 これらの文字列はユニーク制約をかけているので本来は保存されるべき文字列ではない。 エディタ上で文字列を比較してみると、たしかに違っていた。

人間の目ではこれらの文字列の違いをまず見分けることができないだろう。 これらのデータは私が入力したものではないのだが、奇妙な打ち間違いに驚きを隠せない。

s1 = "アンデッドアンラック"
s2 = "アンデッドアンラック"
s1 == s2 #=> false

何が違うのかというと:

  • :通常は 1文字 の「濁点付きカタカナ」です(U+30C7)。
  • 一方、 デ は 2文字で構成されています:
    • (U+30C6)
    • (U+3099)

納得できるような納得できないような。 とにかくこれらの値はRuby上ではべき等ではないということらしい。

この文字列をどちらも等しく扱うためにはUnicode正規化を行う必要があるようだ。

s1 = "アンデッドアンラック"
s2 = "アンデッドアンラック"
s1.unicode_normalize(:nfc) == s2.unicode_normalize(:nfc) #=> true
形式 内容
:nfc 合成形式(推奨)
:nfd 分解形式
:nfkc 互換合成形式(フォーマット統一もする)
:nfkd 互換分解形式

それぞれの引数では正規化の方法を選べるようではあるが、:nfcが推奨らしい。

普段何気なく意識せずに行う文字を入力する行為。 エンコードが一致せずに文字化けするといった事は久しくなかったが、同じUnicodeでもこういった問題が起こるらしい。 奥が深い。