明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1385|回复: 11

[讨论] (autolisp递归算法)整数转罗马数字

[复制链接]
发表于 2022-11-16 17:16:13 | 显示全部楼层 |阅读模式
本帖最后由 freedom_ice 于 2022-11-17 08:39 编辑

刷算法,整数转为罗马数字,用递归方法。供讨论学习。

另求助,用正则表达式应该可以判断一个字符串是否是合法的罗马数字?
搜到如下匹配规则。待验证。
  1. 未经验证的罗马数字:

  2. ^[MDCLXVI]+$

  3. 严格验证罗马数字:

  4. ^(?=[MDCLXVI])M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{ 0,3})$

  5. 灵活验证罗马数字:

  6. ^(?=[MDCLXVI])M*(C[MD]|D?C*)(X[CL]|L?X*)(I[XV]|V?I*)$

  7. 简单的罗马数字:

  8. ^(?=[MDCLXVI])M*D?C{0,4}L?X{0,4}V?I{0,4}$
复制代码
  1. 罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。

  2. 字符          数值
  3. I             1
  4. V             5
  5. X             10
  6. L             50
  7. C             100
  8. D             500
  9. M             1000
  10. 例如, 罗马数字 2 写做 II ,即为两个并列的 1 。12 写做 XII ,即为 X + II 。 27 写做  XXVII, 即为 XX + V + II 。

  11. 通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:

  12. I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
  13. X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
  14. C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
  15. 给定一个罗马数字,将其转换成整数。

复制代码
  1. ;;;*****************************************************************************
  2. ;;;*****************************************************************************
  3. ;;;函数名  : digit->roman ******************************************************
  4. ;;;功  能  : 4000以内的整数转罗马数字 ******************************************
  5. ;;;参  数  : num - 整数 ********************************************************
  6. ;;;返回值  : 罗马数字字符串 ****************************************************
  7. ( defun digit->roman( num )
  8.   ( setq roman "" )
  9.   (  cond ( ( >= num 1000 )
  10.             ( progn
  11.                     ( setq quotient ( / num 1000 )
  12.                              remainders ( rem num 1000 )  )
  13.                     ( repeat quotient
  14.                              ( setq roman ( strcat roman "M" ) )
  15.                     )
  16.                     ( setq roman ( strcat roman ( romantodigit remainders ) ) )                    
  17.             )
  18.           )
  19.           ( ( and ( > 1000 num ) ( >=  num 900 ) )
  20.             ( progn   ( setq remainders ( rem num 900 )  )
  21.                      ( setq roman ( strcat "CM" ( romantodigit remainders ) ) )
  22.             )
  23.           )
  24.           ( ( and ( > 900 num ) ( >=  num 500 ) )
  25.             ( progn   ( setq num ( - num 500 )
  26.                             quotient ( / num 100 )
  27.                             remainders ( rem num 100 )  )
  28.                      ( repeat quotient
  29.                               ( setq roman ( strcat roman "C" ) )
  30.                      )
  31.                      ( setq roman ( strcat "D" roman ( romantodigit remainders ) ) )
  32.             )
  33.           )
  34.           ( ( and ( > 500 num ) ( >=  num 400 ) )
  35.             ( progn   ( setq remainders ( rem num 100 ) )                     
  36.                      ( setq roman ( strcat "CD" ( romantodigit remainders ) ) )
  37.             )
  38.           )
  39.           ( ( and ( > 400 num ) ( >=  num 100 ) )
  40.             ( progn   ( setq quotient ( / num 100 )
  41.                             remainders ( rem num 100 )  )
  42.                      ( repeat quotient
  43.                               ( setq roman ( strcat roman "C" ) )
  44.                      )
  45.                      ( setq roman ( strcat roman ( romantodigit remainders ) ) )
  46.             )
  47.           )
  48.           ( ( and ( > 100 num ) ( >=  num 90 ) )
  49.             ( progn   ( setq num ( - num 90 )
  50.                             remainders ( rem num 10 )  )                     
  51.                      ( setq roman ( strcat "XC" ( romantodigit remainders ) ) )
  52.             )
  53.           )
  54.           ( ( and ( > 90 num ) ( >=  num 50 ) )
  55.             ( progn   ( setq num ( - num 50 )
  56.                             quotient ( / num 10 )
  57.                             remainders ( rem num 10 )  )
  58.                      ( repeat quotient
  59.                               ( setq roman ( strcat roman "X" ) )
  60.                      )
  61.                      ( setq roman ( strcat "L" roman ( romantodigit remainders ) ) )
  62.             )
  63.           )
  64.           ( ( and ( > 50 num ) ( >=  num 40 ) )
  65.             ( progn   ( setq num ( - num 40 ) )
  66.                      ( setq roman ( strcat "XL" roman ( romantodigit num ) ) )
  67.             )
  68.           )
  69.           ( ( and ( > 40 num ) ( >=  num 10 ) )
  70.             ( progn   ( setq quotient ( / num 10 )
  71.                             remainders ( rem num 10 )  )
  72.                      ( repeat quotient
  73.                               ( setq roman ( strcat roman "X" ) )
  74.                      )
  75.                      ( setq roman ( strcat roman ( romantodigit remainders ) ) )
  76.             )
  77.           )
  78.           ( ( = num 9 )
  79.             ( setq roman "IX" )
  80.           )
  81.           ( ( = num 8 )
  82.             ( setq roman "VIII" )
  83.           )
  84.           ( ( = num 7 )
  85.             ( setq roman "VII" )
  86.           )
  87.           ( ( = num 6 )
  88.             ( setq roman "VI" )
  89.           )
  90.           ( ( = num 5 )
  91.             ( setq roman "V" )
  92.           )
  93.           ( ( = num 4 )
  94.             ( setq roman "IV" )
  95.           )
  96.           ( ( = num 3 )
  97.             ( setq roman "III" )
  98.           )
  99.           ( ( = num 2 )
  100.             ( setq roman "II" )
  101.           )
  102.           ( ( = num 1 )
  103.             ( setq roman "I" )
  104.           )
  105.           ( ( = num 0 )
  106.             ( setq roman "" )
  107.           )
  108.   )
  109. )
  110. ;;;*****************************************************************************
  111. ;;;*****************************************************************************
  112. ;;;*****************************************************************************
  113. ( defun c:xx()
  114.   ( setq ss ( getint "\n>>>>>>>>>>输入整数:" ) )
  115.   ( digit->roman ss )  
  116. )
复制代码

发表于 2022-11-16 22:00:32 | 显示全部楼层
(defun df(N)
   (setq str "")
   (cond
      ((>= N 1000) (progn (repeat (/ N 1000) (setq str (strcat "M" str))) (setq str (strcat str (df (rem N 1000))))))
      ((and (> 1000 N) (>= N 900)) (setq str (strcat "CM" (df (rem (- N 900) 1000)))))
      ((and (> 900 N) (>= N 500)) (setq str (strcat "D" (df (rem (- N 500) 1000)))))   
      ((and (> 500 N) (>= N 400)) (setq str (strcat "CD" (df (rem (- N 400) 100)))))
      ((and (> 400 N) (>= N 100)) (progn (repeat (/ N 100) (setq str (strcat "C" str))) (setq str (strcat str (df (rem N 100))))))       
         ((and (> 100 N) (>= N 90)) (setq str (strcat "XC" (df (rem (- N 90) 10 )))))
     ((and (> 90 N) (>= N 50))  (setq str (strcat "L"  (df (rem (- N 50) 100)))))
     ((and (> 50 N) (>= N 40)) (setq str (strcat "XL" (df (rem (- N 40) 10)))))
     ((and (> 40 N) (>= N 10)) (progn (repeat (/ N 10) (setq str (strcat "X" str))) (setq str (strcat str (df (rem N 10))))))
         ((and (> 10 N) (>= N 9)) (setq str (strcat "IX" (df (rem (- N 9) 10)))))
     ((and (> 9 N) (>= N 5)) (setq str (strcat "V" (df (rem (- N 5) 10)))))
     ((and (> 5 N) (>= N 4)) (setq str (strcat "IX" (df (rem (- N 4) 10)))))
         (t  (progn (if (= N 0) (setq str "") (repeat N (setq str (strcat "I" str))))))
   )
)

点评

赞一个! 这是一个很好的理解递归的例子。  发表于 2022-11-17 08:43
回复 支持 1 反对 0

使用道具 举报

发表于 2022-11-17 11:42:03 | 显示全部楼层
学习了,我一直认为罗马数值只有I V X,原来还有其它的
(setq str (list "Ⅰ" "Ⅱ" "Ⅲ" "Ⅳ" "Ⅴ" "Ⅵ" "Ⅶ" "Ⅷ" "Ⅸ" "Ⅹ" "Ⅺ" "Ⅻ"))
(mapcar 'VL-STRING->LIST str);===>((162 241) (162 242) (162 243) (162 244) (162 245) (162 246) (162 247) (162 248) (162 249) (162 250) (162 251) (162 252))
(setq str (list "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" "11" "12"))
(mapcar 'VL-STRING->LIST str);;==>((49) (50) (51) (52) (53) (54) (55) (56) (57) (49 48) (49 49) (49 50))
 楼主| 发表于 2022-11-17 12:09:21 | 显示全部楼层
罗马数字字符串转为整数,不进行罗马数字合法性判断。
  1. ;;;*****************************************************************************
  2. ;;;*****************************************************************************
  3. ;;;函数名  : Roman->digit ******************************************************
  4. ;;;功  能  : 罗马数字转为整数,不进行合法性判断 ********************************
  5. ;;;参  数  : str- 罗马数字字符串 ***********************************************
  6. ;;;返回值  : 整数 **************************************************************
  7. ( defun Roman->digit ( str )
  8.         ( setq roman_digit_dic ( list ( cons "I" 1 )
  9.                                                                                                                                 ( cons "V" 5 )
  10.                                                                                                                                 ( cons "X" 10 )
  11.                                                                                                                                 ( cons "L" 50 )
  12.                                                                                                                                 ( cons "C" 100 )
  13.                                                                                                                                 ( cons "D" 500 )
  14.                                                                                                                                 ( cons "M" 1000 )
  15.                                                                                )               
  16.         )       
  17.         ( setq digit_roman_dic ( list ( cons 1 "I" )
  18.                                                                                                                                 ( cons 5 "V" )
  19.                                                                                                                                 ( cons 10 "X" )
  20.                                                                                                                                 ( cons 50 "L" )
  21.                                                                                                                                 ( cons 100 "C" )
  22.                                                                                                                                 ( cons 500 "D" )
  23.                                                                                                                                 ( cons 1000 "M" )                                                                                                       
  24.                                                                                )               
  25.         )
  26.         ( setq i 1 )
  27.         ( setq num 0 )
  28.         ( repeat ( - ( strlen str ) 1 )
  29.                 ( setq value_i ( cdr ( assoc ( substr str i 1 ) roman_digit_dic ) ) )
  30.                 ( setq value_i+1 ( cdr ( assoc ( substr str ( + i 1 ) 1 ) roman_digit_dic ) ) )
  31.                 ( if ( < value_i value_i+1 )
  32.                                  ( setq num ( - num value_i ) )
  33.                                  ( setq num ( + num value_i ) )
  34.                 )
  35.                 ( setq i ( 1+ i ) )               
  36.         )
  37.         ( setq num ( + num value_i+1 ) )
  38. )
  39. ;;;*****************************************************************************
  40. ;;;*****************************************************************************
  41. ;;;*****************************************************************************
复制代码
发表于 2022-11-17 14:38:43 | 显示全部楼层
罗马写数字的大数还有上划线的,这些更难搞,另外罗马数字很多地方书写不规范,到处用大写字母I,V,X,然后随意组合实际是不正确的,规范的罗马数字是没有半角字符的
 楼主| 发表于 2022-11-17 15:30:14 | 显示全部楼层
llsheng_73 发表于 2022-11-17 14:38
罗马写数字的大数还有上划线的,这些更难搞,另外罗马数字很多地方书写不规范,到处用大写字母I,V,X,然 ...

是的 罗马数字的合法性判断很困难
也没有统一的书写规范
发表于 2022-11-17 16:02:12 | 显示全部楼层
freedom_ice 发表于 2022-11-17 15:30
是的 罗马数字的合法性判断很困难
也没有统一的书写规范

只要人能判断出来,机器也就能判断出来。
发表于 2022-11-18 13:36:21 | 显示全部楼层
llsheng_73 发表于 2022-11-17 14:38
罗马写数字的大数还有上划线的,这些更难搞,另外罗马数字很多地方书写不规范,到处用大写字母I,V,X,然 ...

你这个说法是不对的。罗马数字本来就是用拉丁字符进行组合,8 实际上就是 VIII,写成 Ⅷ 不过就是 Unicode 为常用的数值比较小的罗马数字提供一个单独的码位方便用于有序列表的编号而已。就好像同样会有阿拉伯数字有自己的码位,比如: &#12876;(324C)⒛ (249B),除了用作有序列表的编号时,你在正常表达20的时候规范的用法就是用一个2和一个0,没有必要写成 ⒛ 去使用这个码位的字符(这种用法才是不规范的)。

推荐链接:https://stone-zeng.github.io/2019-02-09-circled-numbers/
发表于 2022-11-18 13:37:34 | 显示全部楼层
本帖最后由 vormittag 于 2022-11-18 13:47 编辑

有些特殊码位的字符,网页上还渲染不出来。。。
罗马数字几乎只会用在文本里,CAD 不以文本排版见长,没有太大的必要在这里搞。文本中的处理可以使用 LaTeX ,数字转换非常方便。
发表于 2022-11-21 18:08:18 | 显示全部楼层
楼主,少了ROMANTODIGIT 这个函数哦,可以补上吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2024-11-16 02:40 , Processed in 0.176595 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表