夏が来た!
夏が来た!
上下の違いが分かる方は居るだろうか?: 同じに見えるけど違う。ブラウザ(かなり古いもの?)やフォントによっては、分かるかも知れない。
答えは、題にあるように、濁音「が」の造りである。今まで知らなかったのだが、Unicodeのひらがな・カタカナは、濁音や半濁音を半角カナ的に 本体+(半)濁点 のように分離して記述し、なおかつ くっつけて一文字のように表示することができる。Combining charactersとかいって、日本語以外でも そういう処理ができるとのことだ。
上の例の「が」は、最初の行はcombining charactersで 「か」+「”」(← 見にくいのでダブルクォートにした) で、2番目は普通に書いてある。全く区別できない。※ 良く出来過ぎていることに、マウスでコピーする時は1文字として扱われるし、等幅フォントのエディタやターミナル(コンソール)でも くっついた状態で表示される。
※おそらく、フォントの字体としては、本体に濁点を加えたものが濁音の文字になっており、combining charactersの濁点は それを再現するような位置に表示されるようにできているのだろう。ただ、この方式ではすべての濁音で濁点が同じ位置に置かれるが、そこはフォントの 描き方でうまく合わせたのだろうか。
↑ ちょっと確かめたら、そう単純なことではないようだ。というのは、下の左図のように、「ヾ」と「ヷ」では濁点の大きさや形が明らかに違うからだ。ということは、フォントに濁点を付けるための情報があるのか、表示する時に、combining charactersの濁点が付く場合は自動で濁音の字に変換されるのか。見たところ、濁点の形が微妙に違う気がする(特に、線の太さ)ので前者なのかも知れないが、本当に そこまでやっているのかという気はする。どちらにしたって、「余計なところに力を入れ過ぎていないか?」と言いたくなる。 (1/22 5:18)
その後、文字に色を付けて濁点を重ねて比べたところ(下の右図)、同じ文字の濁点の形状は、combining charactersでもそうでなくても同様だが、異なる文字同士では異なっている(この例では、「ヾ」の濁点は「ヷ」のより大きい)ことが分かった。 (1/22 14:19)
-
-
濁点の形状の比較 (左: 通常, 右: combining)
-
-
濁点を重ねて比較した。: 「ヾ」の濁点は「ヷ」のより大きい。
僕が見付けた唯一の識別方法は、エディタ(ペーストする)で濁点側から1文字削除することだ。Combining charactersの場合は濁点だけが消えるが、そうでない場合は全部消える。
そして、今回の切っ掛けに関係することは、どういう訳か、Spotifyで出る曲情報(タイトル、アーティスト名、アルバム名)※の中に、本体と濁点・半濁点が分離して記述されたものがあるのだ。全部ではなく、たまにあるのが不思議だ。特定のレーベルという訳でもない気がするが、老舗(例: ビクター、ソニー)や昔の曲に多い気がしている(と書きつつ、1990年代の(一番下の図)もあるので関係ないかも)。
想像だが、レーベルが曲情報を電子形態に登録する際、打ち込む人の癖などで分離してしまったか、それ以前の半角カナも使うシステム(そういうものがあったかは不明)から変換した時に、濁点・半濁点を統合しないままだったのではないか。
※詳しく確認していないのだが、同じSpotifyでも、アプリから取れる情報(Dbusのイベントで取れるもの)とAPIで取れる情報の記述が異なるようだ。前者は分離していることがあるが、後者はそうではない。 ← どちらも同じように分離している場合があることが分かった。例: 飯島真理 「palette(パレット)」(2007)の「パ」。 (1/25 16:31)
それで何も問題が起こらなければ気付かずに過ごせたのだが、自作のSpotifyのミニプレーヤーMinispが駄目だった(これが発端である)。次の左図のように、combining charactersである「が」のあとに空白が出来て、半角カナ的な見苦しさになってしまっている。今見ると、本体(か)と濁点の間隔も少し広い。本来は右側のようになるべきである。
-
-
Minisp: 「が」の「か」と濁点が分離しているため、空白が入っている。
-
-
→ uconvで正規化して解決! (のように思えた)
どうやら、表示に使っているTcl/Tk(wish)がcombining charactersに対応していないようだ(調べた限りではTcl/Tkのページの"Unicode combining characters"の項にはコメントだか状況説明が書いてあるだけのようだし、 そういう設定や属性などがなかったので非対応なのではないか)。
これを何とかしようと調べたら、Rubyのソフト(unicode_utils)の紹介が出て来たものの、インストールするのが面倒なので試行錯誤したら、既存のプログラム iconvでは駄目だったものの、既に入っているパッケージ icu-devtoolsのuconvでできることが分かった。
Combining charactersを まとめる(くっついた文字にする)のは「正規化」という処理で、uconvのマニュアルに例(下記)が書いてあった。
uconv -f utf-8 -t utf-8 \
-x '::nfkc; [:Cc:] >; ::katakana-hiragana;'
上は他の処理も混ざっているので、以下の例のように、曲のタイトル、アーティスト名、アルバム名をそれぞれ正規化してから表示するようにし、上の右図のように解決した。
echo "夏が来た!" | uconv -f utf-8 -t utf-8 -x '::nfc;'
→ 夏が来た!
※正規化処理は、マニュアルではNFKCだが、調べたらNFCのほうが良さそうなので そうした。この辺りは全く詳しくないので手探りだ。また、上のコマンドでnfc前後の :: と ; は なくていいようだが、例にならって付けている。
今 上の参照ページを読んだら、NFCでも今ひとつな場合(「例6: 神と神」)があって気に入らないが、仕方ない(レーベルも、旧字体は余り使わないだろう)。一番いいのは、正規化しなくてもwishで綺麗に表示できるようにすることか。
あるいは、(一番最初に考えた方式の、)uconvでなくプログラムで変換するのがいいか。ひらがな とカタカナだけの対応になるが、濁音・半濁音と そうでない音の文字の順序には概ね規則性(元の音のコード= 濁音-1, 半濁音-2)があるので、それでcombining charactersを くっついた文字に置換するのだ。これなら漢字の旧字体は問題ない。
というか、いちいち計算するのでなく、今の追加処理のテーブル方式で全部処理するほうが良さそうだ。濁音・半濁音は多くないから、テーブルを作るのは容易だ。 → 基本的に、uconvを使うのを止めて追加処理だけにすればできるので、早速そうした。
この方式なら、あとから追加変換が必要になことが分かっても、変換テーブルに追加するだけなので容易だ。 (1/21 17:05)
ところがどっこい!w
下の左図の「グ」のように、なぜか、頑固に正規化できない文字がある(図で「ベ」は くっついているので、処理されていない訳ではないことが分かる)。
-
-
uconvで正規化できない文字(「グ」)があった。
-
-
→ 追加処理で直した。
更に調べたら、どうやらuconv(使っているのは uconv v2.1 ICU 66.1)が正規化しない(素通しする)文字があるようだ。ひらがな・カタカナの濁音・半濁音について調べたところ、以下の文字が駄目だった(正規化されずにそのまま出て来た)。
ど ば べ ぼ ぱ ぺ ぽ ガ ギ グ ズ ゼ ゾ ダ ヷ ヾ
ところで、上の最後のほうにある見慣れない文字、Unicodeにある「ヷ」、「ヸ」、「ヹ」、「ヺ」って実際に使われたのだろうか? どういう読み?? 謎だ。 (→ 4/1に出た、参考になるページがあった。)
その後、PHPの国際化関数のTransliteratorのtransliterator_transliterate()でuconvと同様の正規化処理を試したら、なぜか上の文字も正規化できた。よって、下ではICUやUnicodeのライブラリの問題と書いているが、uconvの問題の可能性が高い。だが、どうしたらこういう抜けが起こるのか見当がつかない。 (1/27 16:08)
実際には、原因はuconvではなく、それが使っているICUやUnicodeのライブラリの問題だろう(日本語に詳しくない人が作った??)から、パッケージを(Linuxディストリビューションのものでない、)オリジナルの最新に入れ替えるか、設定とか調整すれば直せる気はするのだが、パッケージの交換は あとあと面倒になるのでせず、設定・調整はuconvなどのマニュアルを読んでも分からない用語が多くて どうすればいいか分からなかったので、以下のような力技で対応した。
- 起動時(初期化)
- uconvで正規化できない濁音・半濁音を調べてリストを作る。
- それらの正規化後の文字のリストを作る。
- 曲情報(タイトル、アーティスト名、アルバム名)を表示する前
- uconvで正規化する。
- uconvで正規化できなかった文字がある場合は、正規化した文字に置換する。
これなら、将来ICUやUnicodeのライブラリが更新されて、すべての濁音・半濁音が正規化できるようになれば(なんか、永遠にそうならない気が・・・w)、自動的に追加処理が不要になる。
処理を実装し、上の右図のように、駄目だった文字が ちゃんと表示され、(今のところは)一件落着となった。ただ、いつものように、他にも何か問題がありそうなので、表示やログを注視しながら音楽を聴いている。
これ、日本語以外でも あったらお手上げだが、読めなくて気付かないだろうから良し?www
PS. 中程("1/21 17:05"の辺り)に書いたように、これを書いたあとで、実は、uconvを使うのでなく一番最初に思い付いた単純なテーブル変換方式が一番良かったというオチだった(今のところは)。Unicodeの考えは基本的には いいと思うが、(何かで必要なのだろうが)複雑な概念をいろいろ作り出して、それが日本語や実際の用途に合わない、あるいは完全な実装ができていないために、いろいろなところで苦労してそうなのが残念だ。