はじめに
にゃーん。
楽しい5月連休も今日が最終日。残念ながら明日からは仕事をしなければなりません。
今日は小ネタ。TO_NUMBER
/TO_CHAR
でローマ数字をサポートした、というものです。
平たい顔属なので、普段はあまり使わない(映画やゲームのナンバリングくらいでしか使わない?)ローマ数字ですが、PostgreSQLでも今まではサポートしてなかったようです。
概要
Commitfest 2025-01でコミットされた項目である。
タイトル | Add roman support for to_number function |
---|---|
Topic | Performance |
Created | 2024-08-30 07:22:58 |
Last modified | 2025-01-22 20:20:02 |
Emails | [PATCH] Add roman support for to_number function |
PostgreSQL 18での改善内容
PostgreSQL 18では以下の機能が追加された。
-
TO_NUMBER
関数で、ローマ数字から数値への変換が可能になった。 -
TO_CHAR
関数で数値からローマ数字への変換が可能になった。
TO_NUMBER()
ローマ数字から数値に変換する場合には、TO_NUMBER
の第2引数にRN
またはFMRN
を指定する。
ただ、TO_NUMBER
の場合には、ローマ数字文字列をtrimしてから処理するっぽいので、RN
を指定してもFMRN
を指定しても効果は変わらないようだ。
postgres=# SELECT to_number('I', 'RN');
to_number
-----------
1
(1 row)
postgres=# SELECT to_number('I', 'FMRN');
to_number
-----------
1
(1 row)
postgres=# SELECT to_number(' I ', 'RN');
to_number
-----------
1
(1 row)
postgres=# SELECT to_number(' I ', 'FMRN');
to_number
-----------
1
(1 row)
他のローマ数字の例も試してみる(フォーマット指定はRN
のみ試行)。
postgres=# SELECT to_number('XVIII','RN');
to_number
-----------
18
(1 row)
postgres=# SELECT to_number('xvIIi','RN');
to_number
-----------
18
(1 row)
postgres=# SELECT to_number('CCCXXXIV','RN');
to_number
-----------
334
(1 row)
postgres=# SELECT to_number('MMMCMXCIX','RN');
to_number
-----------
3999
(1 row)
ローマ数字のアルファベットは大文字も小文字も(混在しても)指定可能である。
正負記号(+
や-
)を頭につけた場合はエラーになる。
数字文字列途中にローマ数字で規定された英文字(I
,V
,X
,L
,C
,D
,M
)が含まれていた場合には、そこまでの文字列を元に数値への変換を行う。
postgres=# SELECT to_number('CCCXXXIV','RN');
to_number
-----------
334
(1 row)
postgres=# SELECT to_number('-CCCXXXIV','RN');
ERROR: invalid Roman numeral
postgres=# SELECT to_number('+CCCXXXIV','RN');
ERROR: invalid Roman numeral
postgres=# SELECT to_number('CCC.XXXIV','RN');
to_number
-----------
300
(1 row)
postgres=# SELECT to_number('CCC XXXIV','RN');
to_number
-----------
300
(1 row)
TO_CHAR()
数値からローマ数字に変換する場合には、TO_CHAR
の第2引数にRN
またはFMRN
を指定する。
-
RN
を指定した場合は、右詰め文字列となる。 -
FMRN
を指定した場合、左詰め文字列となる。
postgres=# SELECT to_char(1, 'RN');
to_char
-----------------
I
(1 row)
postgres=# SELECT to_char(1, 'FMRN');
to_char
---------
I
(1 row)
postgres=# SELECT to_char(334, 'RN');
to_char
-----------------
CCCXXXIV
(1 row)
postgres=# SELECT to_char(334, 'FMRN');
to_char
----------
CCCXXXIV
(1 row)
postgres=# SELECT to_char(3999, 'RN');
to_char
-----------------
MMMCMXCIX
(1 row)
postgres=# SELECT to_char(3999, 'FMRN');
to_char
-----------
MMMCMXCIX
(1 row)
ローマ数字の範囲って?
そういえばローマ数字の範囲ってどうなっている?と思い。Wikpedia記事(ローマ数字)を見てみた。
現代の一般的な表記法では、1以上4000未満の数を表すことができる。
とのこと。
では、TO_CHAR()
の第1引数に、0、負の数、小数、4000以上の数、を指定したらどうなるのか。
postgres=# SELECT to_char(0, 'RN');
to_char
-----------------
###############
(1 row)
postgres=# SELECT to_char(-1, 'RN');
to_char
-----------------
###############
(1 row)
postgres=# SELECT to_char(3.4, 'RN');
to_char
-----------------
III
(1 row)
postgres=# SELECT to_char(3.5, 'RN');
to_char
-----------------
IV
(1 row)
postgres=# SELECT to_char(3999, 'RN');
to_char
-----------------
MMMCMXCIX
(1 row)
postgres=# SELECT to_char(4000, 'RN');
to_char
-----------------
###############
(1 row)
- 0や負数、4000以上の数字を指定した場合はエラーにならず
###############
という文字列が返却される。-
TO_NUMBER
でフォーマットに誤りが合った場合にはエラーになるが、TO_CHAR()
ではエラーにならない。これは他のTO_CHAR()
の流儀に倣ったものなのだろう。
-
- 小数を指定した場合には、それを
ROUND()
した結果をローマ数字に変換する(実際にコードを確認したわけでなく挙動からの推測)。
おわりに
大昔、自分もksjという漢数字型を扱えるジョーク定義型を作ったことがある1ので、こういう変な(?)数値記法を可能にする改善は面白いなあと思っています。
Make Roma Great Again!
-
全然メンテナンスしていないのでたぶん、最近の環境だとビルドできないと思う・・・申し訳ない。 ↩