あらゆる文字に濁点と半濁点を付けてみよう


2018年 04月 15日

まず、以下の文字を見てみよう。

dakutenhandakuten-1.png通常はありえない場合がいっぱいである。
これを見ると、どうやらあらゆる文字に濁点( ゛ )と半濁点( ゜ )を付けることができるようだ。

どうやったらこんな文字(?)を表示できるかを説明する前に、なぜこういうことを調べることになったかの経緯を説明しよう。

ちょっと自然言語処理の練習をするのに、サンプルデータがいろいろあった方が良いので、このところ流行のWebスクレイピングでサンプル集めをした。
そして、集めた文章を、PythonのGUIであるTkinterのTextウィジェットに表示してみたら、こんな状況になってしまった。

dakutenhandakuten-2.pngブラウザ上やエディタ上では(a)のように見えていたのが、TkinterのTextウィジェット上では(b)の表示になってしまった。
半濁点が1つの文字として、1文字分の文字幅を確保して表示されてしまった。

つまり、「パ」が1文字ではなく、「ハ」+「濁点文字」の2文字になっていたからだ。
それでも、多くのブラウザやエディタでは、直前の文字に重ねて濁点・半濁点を表示していたのだが、一部の文字表示ソフトでは、何も考えず、別の文字として表示処理をしているということだ。

これは、Mac系でよく見られる現象であり、こういう状態のWebページに出会ってしまったのである。

上の (b)を(a)に変換する問題に取り組む前に、Pythonでの文字の扱いをちょっと練習しておこう。

次は、’あ’からunicodeの順に40文字を表示したものである。

>>> for i in range(40):
...     print(chr(ord('あ')+i),end='')
...
あぃいぅうぇえぉおかがきぎくぐけげこごさざしじすずせぜそぞただちぢっつづてでとど>>>
>>>

こんな感じで文字処理ができるのだが、詳細は省略する。

さて本題に戻ろう。
pythonで、濁点、半濁点を文字列の中に挿入してみよう。

>>> strlong = 'ハ'+'\u309a'+'ンタ'+'\u3099'+'か'+'\u3099'+'転んた'+'\u3099'+'。'
>>> strlong,len(strlong)
('ハ?ンタ?か?転んた?。', 12)
結果がは「パンダが転んだ。」と見えないが、pythonで上のように実行させれば、多くの場合「パンダが転んだ。」と見えるはずだ。
そして、「パンダが転んだ。」が12文字になっていて、計算は合っている。
これで、濁点、半濁点を分けた文字列を作れることが分かった。

しかし、こんな文字列では大変だ。
このままでは、普通の3文字の「パンダ」で検索しても、マッチングしない。
濁点が別になっていると、処理が困ることがいっぱい出るので、濁点、半濁点を前の文字と一緒にしないといけない。
どんなプログラムを組めば変換できるであろうか。

…と悩む必要はない。 色々な道具が揃っているPythonに、変換ツールがない訳がない。
ということで、次のように unicodedataモジュールを利用することで簡単に済ませた。

>>> import unicodedata
>>> strshort = unicodedata.normalize("NFC",strlong)
>>> strshort,len(strshort)
('パンダが転んだ。', 8)
>>>
上の処理は、Unicode正規化と言われる処理で、文字が合成されるNFC(Normalization Form Canonical Composition)を指定しただけだ。
文字列長は、期待した8文字になっている。

Python上で、文字列をちょろちょろ変換するなら以上で十分だと思うが、ファイル単位で変換したいことがある。
このとき、次のように、文字列のところを標準入力を読み込むメソッドに変更すると、このファイルが、Unixのコマンドのフィルタとして使えて便利だ。

#!/usr/bin/env python

import sys
import unicodedata

print( unicodedata.normalize("NFC", sys.stdin.read()), end='' )

実際、このフィルタで、大量のテキストファイルを”NFC”に変換している。

最初の変な濁点、半濁点がついた文字だが、次のようにして作った。

>>> ' '.join([ch+' '+ch+'\u3099'+' '+ch+'\u309a' for ch in 'さしすせそ'])
'さ さ? さ? し し? し? す す? す? せ せ? せ? そ そ? そ?'
?>>>

dakutenhandakuten-3.png

それ以外も、同様にして作ることができる。
しかし、どの様に表示されるかは、使用環境によって違うので、最初の図のようになるとは限らない。
濁点、半濁点が?に化けているが、これはこの原稿を書き込んでいるMovable TypeがNFD形式を認めず、間違えていると判断し?が表示されている訳である。