eudcで外字を文字コード変換

eudc とは

皆さんの携わるシステムでは外字を使っていますでしょうか。外字とは各文字エンコーディングでユーザ外字領域や私用領域として定められているコードに割り当てられた字のことです。よく知られている用途としては SJIS で動作していたかつての携帯電話で使われていた絵文字があります。

PostgreSQL は、データベースのサーバ文字エンコーディングである UTF8 や EUC_JP、EUC_JIS_2004 において外字を利用可能です。そのコードにどのような字形が割り当てられているかは関知しませんが、外字用とされているコード範囲の文字を読み書きすることができます。

一方で PostgreSQL はクライアント文字エンコーディングからサーバ文字エンコーディングの変換で、一部について外字をサポートしません。日本語の文字エンコーディングでしばしば問題となるのは、サーバ側が UTF8 でクライアント側が SJIS や EUC_JP の場合です。これらの変換では外字はエラーになってしまいます。

eudc は PostgreSQL で UTF8 ⇔ SJIS、UTF8 ⇔ EUC_JP の間で外字の変換を可能にする拡張モジュールです。日本語の全文検索を提供する textsearch-ja のサブプロジェクトとして NTT の板垣貴裕氏の手により開発されましたが、2011年 2月リリースの eudc-1.1.0 を最後に公式的なメンテナンスが途絶えていました。

SRA OSS では、eudc をその後にリリースされた PostgreSQLバージョン(本稿執筆時点で 11.x から 17.x)にも適合するように修正を加えて、eudc 2.x として以下で公開しています。比較的新しい PostgreSQL バージョン系列については Windowsバイナリも提供しています。

リポジトリ
https://github.com/sraoss/eudc

ドキュメント
https://github.com/sraoss/eudc/blob/master/doc/eudc.md

なお、メンテナンスが途絶えたことにも理由があって、UTF8 ⇔ SHIFT_JIS_2004、UTF8 ⇔ EUC_JIS_2004 の間であれば、拡張を導入することなく相当程度に外字領域のコードの変換が可能です。そのため、SJIS と EUC_JP の代替にこれらのコードを使えば良いとも言えます。
しかしながら、SJIS と SHIFT_JIS_2004、EUC_JP と EUC_JIS_2004 はそれぞれ似ていますが別の文字エンコーディングです。外字以外の UTF8 へのマッピングも微妙に異なります。SJIS を使っていたシステムについて外字を使いたいがために SHIFT_JIS_2004 に変えるとなると、それ以外の非互換について影響調査と対応が必要になります。
そのようなわけで、現在も引き続き eudc 拡張を必要とする場合があります。

eudc の使い方

Linux で eudc をソースコードからインストールする手順を説明します。
ソースコードはリポジトリサイトから zip ファイルで、あるいは、リポジトリのクローンを展開することで入手できます。

(zipファイルでダウンロードしてきた場合)
$ unzip eudc-master.zip
$ cd eudc-master

(リポジトリのクローンを展開する場合)
$ git clone https://github.com/sraoss/eudc
$ cd eudc

これを導入先の PostgreSQL のコマンドにパスが通った状態で、以下の make コマンドでビルドして、インストールすることができます。

$ make USE_PGXS=1
$ su -c 'make install'

Windows の場合には、以下のリリースページからバイナリセットが入手できます。

https://github.com/sraoss/eudc/releases

eudc-2.2.0-PG17-win64.zip などの zipファイルを展開すると、以下のファイルが含まれています。

eudc.dll
eudc.control
eudc--2.0.sql
README.md

eudc.dll を PostgreSQL インストール先の lib フォルダに、eudc.control と eudc–2.0.sql を share\extension フォルダに、コピーしてください。eudc–2.0.sql については今後のバージョンアップでバージョン番号部分が変わったり、.sql ファイルが増えたりすると見込まれます。本例で 2.2 バージョンであるのに euc–2.0.sql というファイル名であるのは、提供している関数の名前や引数、戻り値型は、2.0 以来変わっていないためです。

eudc を使うために postgresql.conf への設定は不要です。

eudc による文字変換はデータベースごとに適用できます。
eudc を適用したいデータベースに接続して以下を実行してください。

$ psql -U postgres -d db1
db1=# CREATE EXTENSION eudc;
WARNING:  Perform "SELECT disable_eudc(); DROP EXTENSION eudc;" to drop this extension.
DETAIL:  The 4 system conversions (sjis_to_utf8, utf8_to_sjis, euc_jp_to_utf8, utf8_to_euc_jp) should be reset as default.
CREATE EXTENSION

WARNING メッセージが出ました。これは eudc の使用を止めるときには、「DROP EXTENSION eudc;」の前に必ず「SELECT disable_eudc();」を実行してください、ということを言っています。この意味はこの後で説明します。

「CREATE EXTENSION eudc;」で外字に対応した変換関数が導入されますが、この時点ではまだ使われません。実際に使われるようにするには、CREATE CONVERSION コマンドで、文字コード変換に eudc の関数を使うものと登録しなければなりません。また、UTF8 と EUC_JP や SJIS の間の文字コード変換は既に存在しますので、既存の変換が使われないようにすることも必要です。

eudc にはこれを簡単に行うための関数が用意されています。enable_eudc() 関数で eudc による変換を登録してかつデフォルトで使われるようにします。逆に disable_eudc() 関数で変換を元に戻します。また、show_eudc() で現在の設定状況を確認できます。無効な状態であれば「Is Default?」が「no」になります。

db1=# SELECT enable_eudc();
 enable_eudc
-------------

(1 row)

db1=# SELECT * FROM show_eudc();
 Conversion Function | Source | Destination | Is Default?
---------------------+--------+-------------+-------------
 sjis_eudc_to_utf8   | SJIS   | UTF8        | yes
 utf8_to_sjis_eudc   | UTF8   | SJIS        | yes
 euc_jp_eudc_to_utf8 | EUC_JP | UTF8        | yes
 utf8_to_euc_jp_eudc | UTF8   | EUC_JP      | yes
(4 rows)

PostgreSQL は依存関係を管理するようになっていて、新しいデータ型をサポートする拡張モジュールを導入したなら、そのデータ型を使っているテーブルが残っている状態では、拡張を削除することができません。残念なことに文字コード変換については今のところ依存関係管理の対象外となっています。そのため、eudc が有効化されている状態であるのに「DROP EXTENSION eudc;」が実行できてしまいます。こうなると文字エンコーディング変換ができません。もとに戻すためには「SELECT disable_eudc();」を実行するのが簡単ですが、その関数はすでにアンインストールされています。「CREATE EXTENSION eudc;」のときに警告が出るのは、この事態を避けるためです。

外字コード変換を試す

eudc ソースツリー下の data ディレクトリには SJIS 外字のサンプル sjis.csv が含まれています。これを使って、外字の変換ができるか試してみます。先ほど eudc を導入したデータベース db1 のサーバ側文字エンコーディングは UTF8 であるものとします。

$ cd data
$ psql -U postgres -d db1

db1(5432)=# CREATE TABLE t1 (c text);
CREATE TABLE
db1=# \encoding SJIS
db1=# \copy t1 from sjis.csv CSV
COPY 1
db1=# \encoding UTF8
db1=# SELECT * FROM t1;
                           c
--------------------------------------------------------
 ABCabc012あいうアイウ亜唖娃
(1 row)

text型の列を一つ持つだけのテーブルを作って、\copy コマンドで sjis.csv を読み込むことができました。エンコーディングを UTF8 に戻してテーブル内容を表示すると、外字が含まれてます。ABC、abc、012、あいう、アイウ、亜唖娃の後に続く 3文字がいずれも外字です。本稿でも外字そのままに記載していますので、見え方は皆さんのブラウザで使われているフォントによって異なるはずです。

eudc では外字を変換不能であることを示すための特定の文字に変換することもできます。以下のように設定パラメータ eudc.fallback_character に 1文字(本例では▼)を指定して、外字を読み込むと、外字部分が▼になります。

db1=# SET eudc.fallback_character TO '▼';
SET
db1=# \encoding sjis
db1=# \copy t1 from sjis.csv CSV
COPY 1
db1=# \encoding UTF8
db1=# SELECT * FROM t1;
                                    c
--------------------------------------------------------------------------
 ABCabc012あいうアイウ亜唖娃
 ABC▼▼▼abc▼▼▼012▼▼▼あいう▼▼▼アイウ▼▼▼亜唖娃▼▼▼
(2 rows)

まとめ

本稿では外字を含めた UTF8 ⇔ SJIS、UTF8 ⇔ EUC_JP の文字コード変換を提供する拡張モジュール eudc について説明しました。

eudc 付属ドキュメントには本稿で記載している事項以外に、外字のマッピング規則および対応している正確なコード範囲、disable_eudc() 関数をイベントトリガを使って「DROP EXTENSION eudc;」に連動して自動実行させる方法、ログレベルを調整する設定パラメータ、について記載がありますので、こちらも参照ください。

eudc は SRA OSS にて引き続き、使う人がよほどに居なくなるまでのしばらくは、メンテナンスを継続していく予定です。