如何将罗马数字转换为十进制数字?

里安·罗查

这会将十进制数字转换为罗马数字:

select  to_char(515, 'RN') from dual;

返回值: DXV

怎么做相反呢?抛出ORA-01722: Invalid number

select to_number('DXV', 'RN') from dual;
亚历克斯·普尔

只是为了好玩,另一种方法是将字符串分成单个和相邻数字组,允许使用标准减法表示法(谢谢,维基百科;将每个单个或相邻对或数字转换为它们的十进制等效项;然后将它们求和:

with t (str) as (select 'MCMLXXXIV' from dual)
select sum(
  case regexp_substr(str, '(CM|M|CD|D|XC|C|XL|L|IX|X|IV|V|I)', 1, level)
    when 'M'  then 1000
    when 'CM' then 900
    when 'D'  then 500
    when 'CD' then 400
    when 'C'  then 100
    when 'XC' then 90
    when 'L'  then 50
    when 'XL' then 40
    when 'X'  then 10
    when 'IX' then 9
    when 'V'  then 5
    when 'IV' then 4
    when 'I'  then 1
  end) as decimals
from t
connect by regexp_substr(str, '(CM|M|CD|D|XC|C|XL|L|IX|X|IV|V|I)', 1, level) is not null;

  DECIMALS
----------
      1984

请注意,正则表达式中搜索项的顺序与其等效的十进制顺序不同;您需要将M之前的CM匹配为减号。

如果您需要做很多事情,那么可能值得创建一个确定性函数(当然,对于递归CTE方法也是如此)。在这种情况下,您可以切换到PL / SQL循环以减少上下文切换:

create or replace function roman_to_decimal(p_roman varchar2)
return number deterministic is
  l_decimal number := 0;
begin
  for i in 1..regexp_count(p_roman, '(CM|M|CD|D|XC|C|XL|L|IX|X|IV|V|I)') loop
    l_decimal := l_decimal +
      case regexp_substr(p_roman, '(CM|M|CD|D|XC|C|XL|L|IX|X|IV|V|I)', 1, i)
        when 'M'  then 1000
        when 'CM' then 900
        when 'D'  then 500
        when 'CD' then 400
        when 'C'  then 100
        when 'XC' then 90
        when 'L'  then 50
        when 'XL' then 40
        when 'X'  then 10
        when 'IX' then 9
        when 'V'  then 5
        when 'IV' then 4
        when 'I'  then 1
      end;
  end loop;

  return l_decimal;
end;
/

select roman_to_decimal('DXV'), roman_to_decimal('MCMLXXXIV')
from dual;

ROMAN_TO_DECIMAL('DXV') ROMAN_TO_DECIMAL('MCMLXXXIV')
----------------------- -----------------------------
                    515                          1984

您可以通过以下方式查看并检查所有转化(1-3999,因为这是所支持的范围to_char()):

with t (orig, roman) as (
  select level, to_char(level, 'RN') from dual connect by level < 4000
)
select orig, roman, roman_to_decimal(roman)
from t;

      ORIG ROMAN           ROMAN_TO_DECIMAL(ROMAN)
---------- --------------- -----------------------
         1               I                       1
         2              II                       2
         3             III                       3
         4              IV                       4
         5               V                       5
         6              VI                       6
         7             VII                       7
         8            VIII                       8
         9              IX                       9
        10               X                      10
        11              XI                      11
...
      3994       MMMCMXCIV                    3994
      3995        MMMCMXCV                    3995
      3996       MMMCMXCVI                    3996
      3997      MMMCMXCVII                    3997
      3998     MMMCMXCVIII                    3998
      3999       MMMCMXCIX                    3999

或只是为了验证它们都转换回原始值:

with t (original, roman) as (
  select level, to_char(level, 'RN') from dual connect by level < 4000
)
select original, roman, roman_to_decimal(roman)
from t
where roman_to_decimal(roman) != original;

no rows selected

对于我来说,这比递归CTE慢得多,但在其他版本和平台上可能有所不同。就像我说的,只是为了好玩...

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

将罗马数字转换为十进制

罗马数字转换为十进制数字,获取垃圾值

将罗马数字转换为十进制值错误

八度/ MATLAB函数将罗马数字转换为十进制数

如何将ASCII字符串转换为十进制数字?

如何将数字的最后两个零转换为十进制数字

无法将十进制数字转换为SqlDecimal

将十进制数字转换为ASCII

将十进制数字转换为Excel字母

将货币转换为十进制数字JavaScript

如何将整数转换为罗马数字?

使用python将十六进制十进制数字转换为十进制

将数字转换为罗马数字

将数字转换为罗马数字

如何将IEEE 754双精度(64位)格式的十六进制数字转换为十进制数字?

将具有 1 个十进制数字的双数转换为 2 个数字

如何将月份数字转换为罗马数字?

如何在动作脚本3中将指数数字转换为十进制数字?

将大十六进制转换为十进制数字

将非整数十进制数字转换为二进制

将罗马数字转换为整数

将整数转换为罗马数字

如何将十进制数字格式化为2或3位数字?

将String转换为Double以进行计算会导致我出现十进制数字问题,如何将其取整?

如何将Azure备份报告的``持续时间''列转换为带有十进制数字的日期时间

如何防止JSONObject来自json.jar将十进制数字字符串转换为double

将十进制数字字符串转换为BCD的算法

将R中的十进制数字转换为小时,时间或时差

将十进制数字序列转换为Big endian float