PostgreSQL 10のICUコレーションとJIS X 4061

(更新日: 2018/08/13)

PostgreSQL Advent Calendar 9日目用のエントリです。

PostgreSQL 10のICUコレーション(照合順序)サポートの概要と基本的な使い方は以下のエントリに記載しています。ICUコレーションの使い方は以下を参照してください。

PostgreSQL 10のICUコレーションを使うと日本語を普通にソートでき、更に文字順序までカスタマイズできる

今回は日本語ソート順のJIS規格である JIS X 4061-1996にどの程度対応しているのか確かめてみます。

TL;DR; 仕様書にソート順を書く場合、JIS規格のソート順ではなく、Unicode技術標準(特定ICU バージョン)のソート順序であることを明記しておくとよい。

テストにはICU 60と一緒にビルドしたPostgreSQL gitのREL_10_STABLEブランチを使用しました。

JIS X 4061とテストデータ

まず規格を確認する必要があります。JIS検索のページ

http://www.jisc.go.jp/app/jis/general/GnrJISSearch.html

からJIS規格は参照できます。JIS X 4061を読むと、かなり複雑な比較ルールであることが解ります。意図通りにソートされているか確認する為のサンプルが欲しいです。

JIS X 4061にはテスト用のデータが記載されています。

漢字の照合順序も定義していますが、テストデータにはありません。

いくつかバグと思われる順序もあります。「チータ g」は”た行”としては「ちょこ」の前にくるはずですが、「テェタ G」の前になっています。「びゆーあー」< 「ビューアー」となっています。これは平仮名、片仮名、濁音、捨て仮名、長音、長音の特殊ルールが関連したソート結果になります。「びゆーあー」の位置が規格書の仕様に対して正しいのか、判断が難しいです。

PostgreSQLのマニュアルにはJIS X 4061用に必要な照合順序設定が記載されていません。そこでICUを使っているDB2のマニュアルを見てみます。ks-level4(ksは比較の強さ)とひらがな属性が有効な場合にJIS X 4061のソート順序になると記載されています。

Unicode技術標準書を見ると現在ではひらがな属性は廃止されています。ICU 60で利用しようとするとエラーになります。代わりにlevel4の比較の強さを使うようにと記載されています。

実際にテスト用データをソートしてみる

テスト用データは以下のSQLで準備しました。

%は全角にも見えますが、他の記号や英数字は半角なので半角を利用しています。

CREATE COLLATIONで以下のコレーションを作成します。

一つ一つの実行結果を目視で比較するのは手間なので、psqlの-cオプションを使い、以下のような要領で

/usr/local/pgsql-10/bin/psql -p 5410 -h 127.0.0.1 test7 -c ‘select * from jis2 order by t collate “ulev4”;’ > ulev4.txt

ソート結果をテキストファイルに保存します。

lev1.txt、lev2.txt、lev3.txt、lev4.txt、ulev4.txt 、C.txt(バイナリ比較)、ja_JP.txt(libcの照合順序)、def.txt(JISの試験データの順序)

ja-u-ks-level4(lev4.txt)の場合、JIS X 4061相当のソート順序になるハズです。

lev4.txtの中身

ks-level4でソートした結果は以下の通りです。

JIS X 4061のソート結果サンプルとは異る結果になっています。記号のソート順序が異ります。また以下のωなどは最後の方にソートされており明らかに異なります。

試験データ通りの場合との差分は以下の通りです。

「チータ g」以外に「びゆーあー」「テェタ G」の順序も異なっています。(JIS規格の照合ルールを精査していないので「びゆーあー」「テェタ G」もサンプルの誤り?DB2でも試してみたいことろですが省略)

とにかく、ざっと比較の強度が変わるとどうなるか見てみましょう。

def.txtとlev1.txtの差分

 

lev1.txtとlev2.txtの差分

lev2.txtとlev3.txtの差分

lev3.txtとlev4.txtの差分

level3とlevel4では少なくとも記号や英数字、仮名での照合順序の違いはないようです。

lev4.txtのulev4.txtの差分

lev4はja-u-ks-level4、ulev4はund-u-ks-level4ロケールの照合順序の結果です。(jaは日本語、undは言語未定義のロケール)全角を含む英数字ソートの場合、jaとundロケールとの違いはあまりありません。今回のテストデータではかなり違うことが判ります。

他のサンプルソート例との比較

JIS X 4061にはサンプルのソート例が幾つか載っています。

これらのデータを入れてソートしてみます。

PostgreSQLは仮名に関してはサンプルのソート順と同じ結果を出力します。

漢字(名字)もJIS規格に記載されていたサンプルデータですが、こちらの順序は規格書に記載された順序にはなりませんでした。

念の為、日本語のソート順でややこしい”ー”をチェックしてみます。

正しく比較されています。

まとめ

日本語(ja)でレベル4の比較の強度(ks-level4)

Quaternary Level: When punctuation is ignored (see Ignoring Punctuations (§)) at level 1-3, an additional level can be used to distinguish words with and without punctuation (for example, “ab” < “a-b” < “aB”). This difference is ignored when there is a primary, secondary or tertiary difference. This is also known as the level-4 strength. The quaternary level should only be used if ignoring punctuation is required or when processing Japanese text (see Hiragana processing (§)).
http://userguide.icu-project.org/collation/concepts

を使えばカスタマイズ無しでJIS X 4061定義のソート順序になるかも、と期待していましたが、平仮名/片仮名の順序、記号の順序などを変えないテスト用データ通りにはなりません。

平仮名/片仮名は概ねJISの試験用データに近いソート順序になりましたが、試験データの「チータ g」の位置は明らかにおかしいので、規格書に書いてあるとはいえ明らかな誤りがある試験データが確実に正しい、とするには疑問符がつきます。「適合性試験用データ」には「規定の一部ではない」との但し書きもあります。

JIS規格末尾のテスト用データのソート結果を見ると順序を調整しないとダメなように見えますが、JIS規格本文(12p)の「ファン ふあん フアン」の平仮名/片仮名の順序はks-level3/4で正しくソートされています。長音の「ー」の処理も正しいようです。Unicode Technical Standard #10の 1.3 Contextual Sensitivityに記載されている「カー < カア, but キー > キア」も正しく処理できています。

しかし、JIS規格末尾のテスト用データのソート結果からはPostgreSQL 10 + ICU 60 のja-u-ks-level4はJIS規格の平仮名/片仮名ソートに問題があるように見えます。それでも実は規格書の仕様通り(?)なのかも知れません。記号と漢字のソート順は明らかにJIS規格とは異なります。

たかがソート、されどソート、思った様にソートするのはなかなか難しいです。混乱の元なのでJIS規格は間違っていると思われる箇所を修正すると共に、より詳細かつ完全なテストデータを規格と一緒に配布してもらえると助かります。いっそのこと、Unicodeの策定に関わりUnicode規格をそのままJIS規格にした方が話が早いですね。

PostgreSQL 10がICU照合順序をサポートしているとはいっても、JIS X 4061でソートできます!と安請け合いはしない方が良さそうです。そもそもJIS X 4061は20年も前の規格でエラータさえ修正されていません。最新のUnicode技術標準に準拠した方が良いでしょう。

結論: 仕様書にソート順を書く場合、JIS規格のソート順ではなく、Unicode技術標準(特定ICU バージョン)のソート順序であることを明記しておくとよい。

参考リンク

 

Facebook Comments
Pocket