LoginSignup
25
14

More than 3 years have passed since last update.

JavaScriptで濁音や半角カナの処理

Posted at

ひょんな拍子に、JavaScriptで「ガ」のような濁点付きの仮名を「カ」に直さないといけなくなったのですが、テーブルなしで対応できることが判明しました。

NFCとNFD

」と「ガ」、肉眼で見ればほぼ違いがないですが、データとしては全く別物になっています。

  • …文字コードは\u30ac、濁点まで含めて1つの文字
  • ガ…文字コードは\u30ab\u3099、「+結合文字の濁点1

このように、Unicodeでは、「複数のコードポイントを結合した文字」と「結合した状態で1つのコードポイントに登録された文字」の両方が存在していることがあります。視覚的にも意味的にも全く同じものが別なコードで表されていると(正準等価)、検索の際に厄介です。

そのようなときに役立つルールとして、Unicodeは正規化の手順も定義しています。これは4つありますが、まずは2つを取り上げます。

  • NFD…正準等価な文字については、結合文字に分解した形で正規化する
  • NFC…正準等価な文字については、NFDで正規化したものを再度合成した形に正規化する

これを使うことで、1コードポイントで書かれた「ガ」から「カ」を抽出することが可能となります。

JavaScriptから使ってみる

ES6でJavaScriptにもString.prototype.normalize()というメソッド(MDN)が用意され、Unicode正規化を施した文字列を得られるようになっています。引数には、NFCNFDNFKCNFKD(あと2つは後述)の4つがあります。

そして、濁音・半濁音入りの文字列をNFDで正規化すれば、1文字目は清音になるので、これを取り出せば濁点を外せます。逆に、結合文字の濁点を追加してからNFC正規化をかければ、1コードポイントになった濁音入りの仮名が得られます2

console.log(''.normalize('NFD')[0]) // => 'カ'

NFKCとNFKDと半角カナ

Unicode正規化には、NFC・NFD以外に、「意味が同じになる(互換等価)」を基準にしたNFKC・NFKDというものがあります。これは、正準等価の正規化に加えて、

  • 上付き・下付き文字→通常の文字
  • 装飾付き文字の装飾を外す(1
  • 組文字を解体する((㈱)
  • 半角・全角形を使わない形にする(AアAア

のような正規化を行います(NFKCとNFKDの違いはNFCとNFDの違いと同じで、NFKCは結合済み文字を、NFKDはばらした文字を優先します)。ということで、この変換を使えば、全角英数→半角英数、半角カナ→全角カナの変換が可能です(性質上、逆変換はできません)。

注意点

  • String.prototype.normalize()はES6で加わったメソッドですので、IE11には存在しません。そして、Polyfillをやろうにも、Unicodeのテーブルが必要なので、相応の容量を食うことが予想されます。
  • 4つの正規化全ては、もとに戻せません。特に、「CJK互換漢字」という一部の漢字は、見た目が違うものにNFC・NFD正規化でも変わってしまうことがあります(など)。これもあって、macOSでは「CJK互換漢字などを除外してNFD正規化を行う」という我流の方法でファイル名を格納しています。

  1. 単体の濁点()は\u309bという別なコードポイントにあります。 

  2. もちろん、結合済のコードがない場合(鼻濁音のか゚やアイヌ語用のト゚など)は、NFC正規化してもそのままです。 

25
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
14