明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 1026|回复: 4

[讨论] 多参函数说明以及 cl:format 函数及用法说明

[复制链接]
发表于 2022-8-14 03:50:43 | 显示全部楼层 |阅读模式
本帖最后由 vitalgg 于 2022-8-18 07:50 编辑

多参数函数的简单说明

  1. ;; 多参数函数实质是就是把多余的参数当成一个表来处理。没什么特别的。
  2. ;; 比如:我们想实现多个参数的和。
  3. ;; (add 1 2 3 4 5 ...)
  4. ;; => (add '( 1 2 3 4 5 ... ))

  5. ;; 因为 autolisp(源码编译) 不支持 定义多参。我们只需把多参封装成一个表即可。

  6. (defun add2 (a b)
  7.   (+ a b)) ;; 两个数的和(求两个固定参数的和)

  8. ;; 逐个处理写法
  9. (defun add (lst / res)
  10.   (setq res 0)
  11.   (foreach  num lst
  12.       (setq res (add2 res num)))
  13.   res)

  14. ;; 递归写法1
  15. (defun add (lst / res)
  16.   (if (car lst)
  17.       (setq res (car lst))
  18.     (setq res 0))
  19.   (if (cdr lst)
  20.       (setq res (add2 res (add (cdr lst)))))
  21.   res)
  22.       
  23. ;; 递归写法2
  24. (defun add (lst / res)
  25.   (or (setq res (car lst))
  26.       (setq res 0))
  27.   (if (cdr lst)
  28.       (setq res (add2 res (add (cdr lst))))
  29.     res)
  30.   )




Lisp界强大的字符串格式化输出函数 format 的基本功能的简单实现。

format 函数实际上是三个参数,第三个参数可以以多参数的方式输入,也可看成是一个表。
第 1 个参数是 数据流 , t 表示输出到屏幕, nil 返回字符串,stream ,可以是文件流(用open 写方式打开的文件)
第 2 个参数是 格式化字符串。
第 3~n 个参数是给格式化字符串用的实际值。


用法简述:
  ;; 内部函数支持 ~D ~X ~O ~B ~A ~S
  ;; D 十进制整数
  ;; -- 处理D时的前置参数  @ 带正号 , : 每三位用,号分隔,如 +1,000,001
  ;;  $ 小数点后2位,F 浮点数 E 指数形式(受cad变量及版本不同,显示不同)
  ;; -- 处理数字时的前置参数: v 从参数中取得小数的位数, # 剩余的参数的个数作为小数位数。
  ;; A 字符串 S 可 read 读回。
  ;; X 16进制, O 8进制, B 二进制
  ;; TODO: ~R 数字转英文基数。~:R 数字转序数,~@R 罗马数字,~R 旧式罗马数字
  ;; TODO: ~P 是否复数
  ;; ~{ ~} 迭代 (内部函数不支持)
  ;; 条件格式化 ~[ ~]
  ;; TODO: ~:[FAIL~;pass~]

该函数不断更新中,最终代码见: https://gitee.com/atlisp/atlisp-lib/blob/main/src/cl/format.lsp  
  1. ;;; 格式化输出函数 format 的 简单实现。(非内部函数)
  2. ;;;  
  3. (defun format (stream ctrl-string variables
  4.          / flag-instruct  flag-comma number1 number2 result  to-string tmp-str init-flag)
  5.   ;; 内部函数支持 D X O B A S
  6.   ;; D 十进制整数
  7.   ;; -- 处理D时的前置参数  @ 带正号 , : 每三位用,号分隔,如 +1,000,001
  8.   ;;  $ 小数点后2位,F 浮点数 E 指数形式
  9.   ;; -- 处理数字时的前置参数: v 从参数中取得小数的位数, # 剩余的参数的个数作为小数位数。
  10.   ;; A 字符串 S 可 read 读回。
  11.   ;; X 16进制, O 8进制, B 二进制
  12.   ;; TODO: ~R 数字转英文基数。~:R 数字转序数,~@R 罗马数字,~R 旧式罗马数字
  13.   ;; TODO: ~P 是否复数
  14.   ;; ~{ ~} 迭代 (内部函数不支持)
  15.   ;; 条件格式化 ~[ ~]
  16.   ;; TODO: ~:[FAIL~;pass~]

  17.   (defun to-string (para)
  18.     (cond
  19.       ((= 'INT (type-of para)) (itoa para))
  20.       ((= 'REAL (type-of para)) (rtos para 2 3))
  21.       ((= 'STR (type-of para)) para)
  22.       ((= 'LIST (type-of para)) (vl-prin1-to-string para ))
  23.       ((= 'SYM (type-of para)) (vl-symbol-name para))
  24.       )
  25.     )
  26.   (defun init-flag ()
  27.     (setq flag-instruct nil
  28.     flag-comma nil
  29.     number1 ""
  30.     number2 ""))
  31.   (init-flag)
  32.   (setq result "")
  33.   (while (/= "" ctrl-string)
  34.     (if flag-instruct
  35.   (cond
  36.     ;; 修饰符
  37.     ((= (ascii ",")(ascii ctrl-string))
  38.      ;; comma
  39.      (setq flag-comma T)
  40.      )
  41.     ((= (ascii "v")(ascii ctrl-string))
  42.      ;; v
  43.      (setq number1 (to-string (car variables)))
  44.      (setq variables (cdr variables))
  45.      )
  46.     ((= (ascii "#")(ascii ctrl-string))
  47.      ;; #
  48.      (setq number1 (to-string (length variables)))
  49.      (setq variables (cdr variables))
  50.      )
  51.    
  52.     ((and (> (ascii ctrl-string) 47)
  53.     (> 58 (ascii ctrl-string)))
  54.      ;; 数字
  55.      (if flag-comma
  56.          (setq number2 (strcat number2 (substr ctrl-string 1 1)))
  57.          (setq number1 (strcat number1 (substr ctrl-string 1 1)))
  58.          ))

  59.     ((=  (ascii "~") (ascii ctrl-string)) ;; 处理指令,当连续时,输出~
  60.      (setq result (strcat result "~"))
  61.      (init-flag))
  62.     ((= (ascii "%")(ascii ctrl-string))
  63.      ;; 换行
  64.      (setq result (strcat result "\n"))
  65.      (init-flag))
  66.     ((= (ascii "&")(ascii ctrl-string))
  67.      (setq result (strcat result "\n"))
  68.      (init-flag))
  69.     ((= (ascii "A")(ascii (strcase (substr ctrl-string 1 1))))
  70.      ;; 字符串
  71.      (setq result (strcat result (to-string (car variables))))
  72.      (setq variables (cdr variables))
  73.      (init-flag))
  74.     ((= (ascii "D")(ascii (strcase (substr ctrl-string 1 1))))
  75.      ;; 整数及小数
  76.      (if (/= "" number1) ; 处理占位符
  77.          (progn
  78.      (setq tmp-str  (to-string (car variables)))
  79.      (if (> (atoi number1)(strlen tmp-str))
  80.          (repeat (- (atoi number1)(strlen tmp-str))
  81.            (setq result (strcat result " "))))
  82.      (setq tmp-str "")))
  83.      (setq result (strcat result (to-string (car variables))))
  84.      (setq variables (cdr variables))
  85.      (init-flag))
  86.     ((= (ascii "F")(ascii (strcase (substr ctrl-string 1 1))))
  87.      ;; 浮点数
  88.      (if (= "" number2)
  89.          (setq tmp-str (rtos (car variables) 2 3))
  90.          (setq tmp-str (rtos (car variables) 2 (atoi number2))))
  91.      (if (/= "" number1) ; 处理占位符
  92.          (progn
  93.      (if (> (atoi number1)(strlen tmp-str))
  94.          (repeat (- (atoi number1) (strlen tmp-str))
  95.            (setq result (strcat result " "))))))
  96.      (setq result (strcat result tmp-str))
  97.      (setq tmp-str "")
  98.      (setq variables (cdr variables))
  99.      (init-flag))
  100.     ((= (ascii "E")(ascii (strcase (substr ctrl-string 1 1))))
  101.      ;; 指数形式
  102.      (if (= "" number2)
  103.          (setq tmp-str (rtos (car variables) 1 3))
  104.          (setq tmp-str (rtos (car variables) 1 (atoi number2))))
  105.      (if (/= "" number1) ; 处理占位符
  106.          (progn
  107.      (if (>  (atoi number1)(strlen tmp-str))
  108.          (repeat (- (atoi number1) (strlen tmp-str))
  109.            (setq result (strcat result " "))))))
  110.      (setq result (strcat result tmp-str))
  111.      (setq tmp-str "")
  112.      (setq variables (cdr variables))
  113.      (init-flag))   
  114.     ((= (ascii "$")(ascii (strcase (substr ctrl-string 1 1))))
  115.      ;; 货币
  116.      (if (= "" number1)
  117.          (setq result (strcat result (rtos (car variables) 2 2)))
  118.          (setq result (strcat result (rtos (car variables) 2 (atoi number1)))))
  119.      (setq variables (cdr variables))
  120.      (init-flag))
  121.    
  122.     )
  123.   (cond
  124.     ((=  (ascii "~") (ascii ctrl-string)) ;; 处理指令,当连续时,输出~
  125.      (setq flag-instruct T))  
  126.     (t
  127.      (setq result (strcat result (substr ctrl-string 1 1)))
  128.      )))
  129.     (setq ctrl-string (substr ctrl-string 2)))

  130.   (cond
  131.     ((= T stream)
  132.      (princ result)
  133.      (princ))
  134.     ((= nil stream)
  135.      result)
  136.     ((= (type stream) 'FILE)
  137.      (write-line result stream))
  138.     )
  139.   )
  140.   


AutoCAD 中实现多参

autocad的 lisp 编译器不支持多参的写法编译,所以我们只能通过 修改 fas 文件的方法实现多参。
如下面两个图。第一个是源文件编译后的。第二个是修改后的。加载第二个文件就可以实现多参写法。
直接编译的文件:


修改以实现多参数:



使用示例

可变参数用法,加载 修改后的 fas ,按下图方式调用。



如果在其它CAD使用的话,可以不修改fas 将第三个及以后的参数写成表的形式就可以了。
原生 fas 的固定参数用法



format 写数据流



该函数已包含在 @lisp  base中。安装了 @lisp 就可以使用,但是这种方法不兼容其它CAD,如浩辰,中望等。所以没有再更新了。

更多内容,请访问 @lisp 开源项目 https://gitee.com/atlisp


新增 cl 类函数,以山寨 commonlisp 的一些函数。如 cl:format





马上实践:
他们说:有遮挡更性感。
将以下代码复制到 CAD 命令行内,回车即可开始安装 @lisp kernel。@lisp kernel(内核)包含 @lisp函数库 及 @lisp应用云 的基本管理功能。
(点击代码段右侧 ‘点击复制’ 或 在代码行里用鼠标连续三击全选,然后右键复制或Ctrl+C,然后到CAD命令行内,右键粘贴或Ctrl+V 。)
完成后即可使用 cl:format 函数进行试验。
  1. (progn(vl-load-com)(setq o"http://atlisp.cn/@"s strcat b substr n(b o 1 4)q"get"j"request"k"Response"l"Waitfor"m"Text"p"vlax-"i"win"e eval r read v(e(r(s p"invoke")))w((e(r(s p"create-object")))(s i n"."i n j".5.1")))(v w'open q o :vlax-true)(v w'send)(v w(r(s l k))1000)(e(r((e(r(s p q)))w(r(s k m))))))



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x

评分

参与人数 1明经币 +1 金钱 +18 收起 理由
highflybird + 1 + 18 很给力!

查看全部评分

"觉得好,就打赏"
还没有人打赏,支持一下
发表于 2022-8-14 15:10:30 | 显示全部楼层
本帖最后由 guosheyang 于 2022-8-14 15:13 编辑

用列表模拟多参 这样还简洁点
;求多个数的平均数(列表中原子个数不定)
;执行(ave'(2 3 4 5 6 8 9 12))         
(defun ave(L)
(/(apply'+ L)
   (float(length L)))
)
;求多个数的和列表中原子个数不定)
;执行(add'(1 2 3 4 6 7))         
(defun add(L)
  (apply'+ L)
)
;求多个数的差           
;执行(sub'(1 2 3 4 6 7))
(defun sub(L)
  (apply'- L)
)
;求多个数的积               
;执行(multiply'(1 2 3 4 6 7))
(defun multiply(L)
  (apply'* L)
)
;求多个数的商            
;执行(devide '(1 2 3 4 6 7))
(defun devide(L)
  (apply'/(mapcar'float L))
)
 楼主| 发表于 2022-8-14 18:38:40 | 显示全部楼层
guosheyang 发表于 2022-8-14 15:10
用列表模拟多参 这样还简洁点
;求多个数的平均数(列表中原子个数不定)
;执行(ave'(2 3 4 5 6 8 9 12))  ...

对的,不是说用列表模拟多参。
而是多参 在程序实际内存运行中就是作为一个列表进行处理的。
 楼主| 发表于 2022-8-15 22:58:20 | 显示全部楼层
本帖最后由 vitalgg 于 2022-8-17 17:22 编辑

浩辰不支持可变参数,
中望可以。但是要转zelx
 楼主| 发表于 2022-8-17 19:37:21 | 显示全部楼层
format 用法简述
用法简述:
  ;; 内部函数支持 ~D ~X ~O ~B ~A ~S
  ;; D 十进制整数
  ;; -- 处理D时的前置参数  @ 带正号 , : 每三位用,号分隔,如 +1,000,001
  ;;  $ 小数点后2位,F 浮点数 E 指数形式(受cad变量及版本不同,显示不同)
  ;; -- 处理数字时的前置参数: v 从参数中取得小数的位数, # 剩余的参数的个数作为小数位数。
  ;; A 字符串 S 可 read 读回。
  ;; X 16进制, O 8进制, B 二进制
  ;; TODO: ~R 数字转英文基数。~:R 数字转序数,~@R 罗马数字,~R 旧式罗马数字
  ;; TODO: ~P 是否复数
  ;; ~{ ~} 迭代 (内部函数不支持)
  ;; 条件格式化 ~[ ~]
  ;; TODO: ~:[FAIL~;pass~]
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-15 15:12 , Processed in 0.206473 second(s), 27 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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