twitter-cldr-rbの日本語文字列照合順序をsort_kana_jisx4061と比較
拙作sort_kana_jisx4061を仲間内で紹介したところ、ICU(International Components for Unicode)をRubyで実装したtwitter-cldr-rbというのがあると教えてもらいました。
twitter-cldr-rbはCLDR(Common Locale Data Repository)にもとづいてデータをRubyで国際化処理するもので、さまざまな機能があります。ここではsort_kana_jisx4061と同様の日本語文字列照合順序の機能を比較してみます。
twitter-cldr-rbでできること
twitter-cldr-rbのREADME.mdを見ると、さまざまな国際化の機能があります。数字の桁区切り(カンマかピリオドかなど)、重さや長さの単位、通貨の単位、数字を言葉で書く、日時の表記、月日の表記、列挙などに対応しています。
その1つとして、対象ロケールでの文字列照合順序が実装されています。
照合順序のデータは、ソースの「/resources/collation/tries/」ディレクトリに、マーシャルされたバイナリデータとして用意されています。ja.dumpは201KBのようです。
比較してみる
twitter-cldr-rbは、RubyGemsからインストールできます。
$ gem install twitter-cldr-rb
ここでは、元の文字列と読みをタブで区切った1行1項目のテキストから、日本語文字列照合順序でソートした元の文字列のリストを出力することにします。
twitter-cldr-rbでは通常、照合順序にもとづいたソートには、ArrayからLocalizedArrayを作ってsortメソッドを呼び出します。が、そのままでは「元の文字列と読みからなるHashを、読みでソートする」ということができません。
そこで、1つ下のレイヤーのメソッドを呼び出してソートします。
#!/usr/bin/env ruby require 'twitter_cldr' JACOL = TwitterCldr::Collation::Collator.new(:ja) def sort_kana_cldr_by(enum) enum.sort_by {|x| JACOL.get_sort_key(yield(x)) } end alldat = [] ARGF.each_line do |line| word, yomi = line.chomp.split(/\t/) alldat << { word: word, yomi: yomi } end sort_kana_cldr_by(alldat) {|x| x[:yomi]}.each do |x| puts x[:word] end
比較対象として、sort_kana_jisx4061でも同じ働きをするものを作ります。
#!/usr/bin/env ruby require 'sort_kana_jisx4061' alldat = [] ARGF.each_line do |line| word, yomi = line.chomp.split(/\t/) alldat << { word: word, yomi: yomi } end sort_kana_jisx4061_by(alldat) {|x| x[:yomi]}.each do |x| puts x[:word] end
この両方に手持ちのデータをかけた結果、同じ出力になることを確認しました。
「劉備と諸葛亮 カネ勘定の『三国志』」
「素人は戦略を語り、玄人は兵站を語る」としばしば言われる。本書は古代中国の経済や貨幣の研究者が「三国志」の世界を財源や経済政策から語る本だ。
まず曹操は、黄巾一派の残党を吸収し、屯田で働かせて財政基盤とした。「三国志」には詳しくないけど、このあたりは「蒼天航路」でも大きく取り上げられてたな。
一方、劉備は徐州牧時代には糜竺をパトロンにして経済的にまず安定。荊州牧についたときには、劉備に信用がなかったので諸葛亮の名前で金を集めた。諸葛亮はここで、無戸籍民を集めて戸籍に登録し、税収を増やした。
諸葛亮は劉備のもとについたとき、天下三分の計ではなく「隆中対」という策を授けた。内容は、荊州と益州(蜀)は経済的利益があるからいただけ、南征しろ、しかる後に長安方面に向かえ、というものだったとか。
というわけで劉備が入蜀したとき、成都城の蔵の財宝を接収し、ほぼ空にしてしまった。そこで貨幣を改鋳して質を落として国庫を充たした。
南征では、諸葛亮は土地の人々を「生かさず殺さず」で搾取した。その資金を北伐にあてた。つまり、南征で得た資金は、益州にあまり還元されず、北伐の軍資金となった。そのほか、屯田や略奪で資金や物資を得たとか。なお、五丈原の最後の北伐は、前回から3年のブランクがあり、蜀漢の食料事情が悪化していたのが原因だろうと。
このような諸葛亮の軍事最優先型経済を、著者は、自国よりはるかに強大な曹魏と対決するために無理をしていたのだろうと分析している。
ちなみにそのほか、董卓支配下の長安は実は好景気だったとか。また袁術は、貿易地を手に入れたことにより、ほかの群雄が飢饉に苦しむ中で多くの冨と食料を保有したし、飢饉に陥ったときにも対策をとっていたとか。
jpholidaypのローカルタイム依存をなくす問題
「(日本で)今日が休日かどうか」を判定するjpholidaypというツールを公開しています。100行ぐらいのPythonスクリプトです。もともと、素に近いサーバーにスクリプトを1つ入れるだけでcronから使える、というコンセプトで作りました。
jpholidaypのコードでは、「今日」の判定に、ローカルタイムがJST(日本時間)であることを前提にしています。しかし、ちょうどサマータイム論議もあるところだったりして、それってダサいよなーと思っています。
ただまあ、Python 2/3両対応とか、(できるだけ)追加モジュール不要とかを考えるといろいろ面倒だなあと。
今日を求めるコードは、現状ではこんな感じ。
from datetime import date today = date.today()
明示的にJSTを指定すると、Python 3ではこうなります。ただしPython 2では使えません。
from datetime import date, datetime, timedelta, timezone JST = timezone(timedelta(hours=9), 'JST') today = datetime.now(JST).date()
Python 2でも使えるようにするには、こうなります。
from datetime import date, datetime, timedelta, tzinfo class JST(tzinfo): def utcoffset(self, dt): return timedelta(hours=9) def tzname(self, dt): return 'JST' def dst(self, dt): return timedelta(0) today = datetime.now(JST()).date()
ただ、いずれにしても時差9時間固定で、サマータイムなどには対応していません。
そこで、Python 2/3とも、pytzライブラリを使えば、タイムゾーンのデータベースを使えます。
from datetime import date, datetime import pytz JST = pytz.timezone('Asia/Tokyo') today = datetime.now(JST).date()
ただ、pytzライブラリを追加する必要があるのが、冒頭のコンセプトからすると、少しだけ考えてしまうところです。
とりあえずpytzによる実装をpytzブランチに置いておきました。