わりとマイナーな機能ですが、linuxでja_JP.utf8のlocaleで以下のようにコマンドを叩くと、元号をちゃんと処理して表示してくれたりします。
$ LC_TIME=C date +'%EY'ちょっと前に国の象徴のおじいさん(82)が「退位したい」みたいなこと言ってましたし、いいかげん年なのでしんどかろうと思います。法律の要件とかはわかりませんが退位が行われれば元号が変わるでしょうから、庶民の我々も少なくともこのコードを修正しないといけないわけです。
2016
$ LC_TIME=ja_JP.utf8 date +'%EY'
平成28年
これはどこからきているのかを探りましょう。
$ ldd `which date`シンプル。linux kernel, dateコマンドの中身, libcのどれかに絞られました。
linux-vdso.so.1 (0x00007ffd14593000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fea550ed000)
/lib64/ld-linux-x86-64.so.2 (0x000056070c37e000)
kernelはありえないので候補から外します。心配な人はstraceでもして安心してください。
date本体もないと思っているのですが念の為確認します。
$ LC_TIME=ja_JP.utf8 ltrace date +'%EY'libcのstrftimeがやっているようです。man 3 strftime を見ます。
(中略)
strftime(" \345\271\263\346\210\22028\345\271\264", 1024, " %EY", 0x7f8f5c1464a0) = 12
fwrite("\345\271\263\346\210\22028\345\271\264", 11, 1, 0x7f8f5c142600) = 1
(以下略)
(ー略ー)
%E Modifier: use alternative format, see below. (SU)
(ー略ー)
(SU) The Single UNIX Specification mentions %Ec, %EC, %Ex, %EX,
%Ey, %EY, %Od, %Oe, %OH, %OI, %Om, %OM, %OS, %Ou,あ、Single UNIX Specificationで決まってたのか。ってことはきっとAppleのOS Xとかでもつかえるんだろうな。。持ってないので知らないけど。
%OU, %OV, %Ow, %OW, %Oy, where the effect of the O modifier
is to use alternative numeric symbols (say, roman numerals), and
that of the E modifier is to use a locale-dependent alternative
representation.
さて、libcでlocale-dependentだということがわかりました。ソースコードとってきましょう。
$ find glibc-2.24 |grep jaということで以下のファイルに含まれてそうです。
./localedata/locales/ja_JP
./benchtests/strcoll-inputs/lorem_ipsum#ja_JP.UTF-8
./po/ja.po
./debian/po/ja.po
glibc-2.24/localedata/locales/ja_JPいかにもそれらしい「era」というエントリがあります。きっとこれなんですが……
era "<U002B><U003A><U0032><U003A><U0031><U0039><U0039><U0030><U002F><U0030><U0031><U002F><U0030><U0031><U003A><U002B><U002A><U003A><U5E73><U6210><U003A><U0025><U0045><U0043><U0025><U0045><U0079><U5E74>";/
"<U002B><U003A><U0031><U003A><U0031><U0039><U0038><U0039><U002F><U0030><U0031><U002F><U0030><U0038><U003A><U0031><U0039><U0038><U0039><U002F><U0031><U0032><U002F><U0033><U0031><U003A><U5E73><U6210><U003A><U0025><U0045><U0043><U5143><U5E74>";/
"<U002B><U003A><U0032><U003A><U0031><U0039><U0032><U0037><U002F><U0030><U0031><U002F><U0030><U0031><U003A><U0031><U0039><U0038><U0039><U002F><U0030><U0031><U002F><U0030><U0037><U003A><U662D><U548C><U003A><U0025><U0045><U0043><U0025><U0045><U0079><U5E74>";/
"<U002B><U003A><U0031><U003A><U0031><U0039><U0032><U0036><U002F><U0031><U0032><U002F><U0032><U0035><U003A><U0031><U0039><U0032><U0036><U002F><U0031><U0032><U002F><U0033><U0031><U003A><U662D><U548C><U003A><U0025><U0045><U0043><U5143><U5E74>";/
"<U002B><U003A><U0032><U003A><U0031><U0039><U0031><U0033><U002F><U0030><U0031><U002F><U0030><U0031><U003A><U0031><U0039><U0032><U0036><U002F><U0031><U0032><U002F><U0032><U0034><U003A><U5927><U6B63><U003A><U0025><U0045><U0043><U0025><U0045><U0079><U5E74>";/
"<U002B><U003A><U0032><U003A><U0031><U0039><U0031><U0032><U002F><U0030><U0037><U002F><U0033><U0030><U003A><U0031><U0039><U0031><U0032><U002F><U0031><U0032><U002F><U0033><U0031><U003A><U5927><U6B63><U003A><U0025><U0045><U0043><U5143><U5E74>";/
"<U002B><U003A><U0036><U003A><U0031><U0038><U0037><U0033><U002F><U0030><U0031><U002F><U0030><U0031><U003A><U0031><U0039><U0031><U0032><U002F><U0030><U0037><U002F><U0032><U0039><U003A><U660E><U6CBB><U003A><U0025><U0045><U0043><U0025><U0045><U0079><U5E74>";/
"<U002B><U003A><U0031><U003A><U0030><U0030><U0030><U0031><U002F><U0030><U0031><U002F><U0030><U0031><U003A><U0031><U0038><U0037><U0032><U002F><U0031><U0032><U002F><U0033><U0031><U003A><U897F><U66A6><U003A><U0025><U0045><U0043><U0025><U0045><U0079><U5E74>";/
"<U002B><U003A><U0031><U003A><U002D><U0030><U0030><U0030><U0031><U002F><U0031><U0032><U002F><U0033><U0031><U003A><U002D><U002A><U003A><U7D00><U5143><U524D><U003A><U0025><U0045><U0043><U0025><U0045><U0079><U5E74>"
ソースコードのくせに謎エンコードされてて読めないよ! >_<
きっとunicodeの表が頭に全部はいっててデコードできる人は心の目で読めるんですがそんなハンドアセンブルの100倍くらいしんどそうなスキルは持っていません。ちなみにハンドアセンブルも表がないとできません。
しょうがないので<Uxxxx>; みたいなのが来たらxxxx部分にあたるunicode文字に置換する使い捨てスクリプトをシコシコ書きます。
import os, re
def main():
for line in file('ja_JP'):
out = ""これを実行すると.. でました
while 1:
m = re.search('(<U([0-9a-fA-F]+)>;?)', line)
if m:
out = out + line[:m.start()] + unichr(int(m.group(2), base=16))
line = line[m.end():]
else:
out = out + line
break
print out.encode('utf8'),
main()
era "+:2:1990/01/01:+*:平成:%EC%Ey年";/元年だけ別の行になってるんですね…… 明治は6年からなので旧暦のごちゃっとしたあたりは気にしないと。
"+:1:1989/01/08:1989/12/31:平成:%EC元年";/
"+:2:1927/01/01:1989/01/07:昭和:%EC%Ey年";/
"+:1:1926/12/25:1926/12/31:昭和:%EC元年";/
"+:2:1913/01/01:1926/12/24:大正:%EC%Ey年";/
"+:2:1912/07/30:1912/12/31:大正:%EC元年";/
"+:6:1873/01/01:1912/07/29:明治:%EC%Ey年";/
"+:1:0001/01/01:1872/12/31:西暦:%EC%Ey年";/
"+:1:-0001/12/31:-*:紀元前:%EC%Ey年"
というわけで元号の場所はわかりました。おじいさんが退位したらここを直してみんなでglibcをアップデートしよう。
ではでは。
追記
「別ファイルになってないの?」と聞かれたので追記 。
たとえば /usr/share/i18n/locales/ja_JP のように別ファイルになっていて、localedefを使うことで独自のlocaleを定義することもできる。
でもlocaleの設定がおこなわれるのはプロセスの最初のほうで setlocale() されるタイミングだから結局元号の処理更新を反映したいプロセスの再起動が必要なのは変わらないのでした……。
0 件のコメント:
コメントを投稿