明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 18000|回复: 57

[函数] 两个简单的读取excel表格函数

    [复制链接]
发表于 2019-9-7 16:22:37 | 显示全部楼层 |阅读模式
在CAD二次开发中,常需要读取excel表格数据,根据lisp语言的特点,有时一个一个单元格读取反而方便,以下是在实际中常用的两个读取excel表格数据小程序,个人觉得还是比较实用啊:
  1. ;;;;;读取excel据函数
  2. (defun Ljx-read-excel-data (vv hor sh / hor ru) ;;;vv为列数直接输入字母、hor为行数,直接输入数字,sh为工作表对象sheet
  3.   (setq hor (itoa hor))
  4.   (setq ru (vlax-variant-value (msxl-get-value (msxl-get-range sh (strcat vv hor)))))
  5.   ru
  6. )

  7. ;;;;;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
  8. ;;;;;读取excel数据函数输出text格式
  9. (defun Ljx-read-excel-text (vv hor sh / hor ru) ;;;vv为列数直接输入字母、hor为行数,直接输入数字,sh为工作表对象sheet
  10.   (setq hor (itoa hor))
  11.   (setq ru (vlax-variant-value (msxl-get-text (msxl-get-range sh (strcat vv hor)))))
  12.   ru
  13. )

评分

参与人数 1金钱 +20 收起 理由
babylon1386 + 20

查看全部评分

"觉得好,就打赏"
还没有人打赏,支持一下

本帖被以下淘专辑推荐:

发表于 2019-9-11 15:54:47 | 显示全部楼层
  1. ;;;ljx-vlxls-app-Init;子程序局部优化;

  2.       (cond
  3.         ( (wcmatch excelname "*.xls");;;为2003-xls文件时;
  4.             (cond
  5.               ( (setq out2003 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2003))    (setq out (car out2003))    )
  6.               ( (setq out2007 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2007))    (setq out (car out2007))    )
  7.               ( (setq out2010 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2010))    (setq out (car out2010))    )
  8.               ( (setq out2013 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2013))    (setq out (car out2013))    )
  9.               ( (setq out2016 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2016))    (setq out (car out2016))    )
  10.               ( t    (princ "\\n  计算机上未安装excel2003、excel2007、excel2010、excel2013、excel2016,不能打开xls文件!")  )
  11.             );;;cond;
  12.         )
  13.         ( (wcmatch excelname "*.xlsx");;;为2007-xlsx文件时;
  14.             (cond
  15.               ( (setq out2007 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2007))    (setq out (car out2007))    )
  16.               ( (setq out2010 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2010))    (setq out (car out2010))    )
  17.               ( (setq out2013 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2013))    (setq out (car out2013))    )
  18.               ( (setq out2016 (vl-member-if (function (lambda (x) (findfile x)  )) hm-2016))    (setq out (car out2016))    )
  19.               ( t    (princ "\\n  计算机上未安装excel2007、excel2010、excel2013、excel2016,不能打开xls文件!")  )
  20.             );;;cond;
  21.         )
  22.         ( T  (setq out nil)  )
  23.       );;;cond;
  24. ;;;先加载低版本,低版本不存在再加载高版本;;

评分

参与人数 1明经币 +1 收起 理由
babylon1386 + 1

查看全部评分

回复 支持 2 反对 0

使用道具 举报

 楼主| 发表于 2024-6-11 20:07:20 | 显示全部楼层
dalin1985 发表于 2023-5-27 16:49
请问如何实现列数用数字呢?用字母列数太多了不能迭代呀,用着不方便。

这个网上有:
;;;cell id 轉換
(Defun vlxls-cellid (id / xx id1 id2 Rtn)
  (if (= (type id) 'list)
    (setq id (vlxls-rangeid id))
  )
  (setq id (strcase id))
  (if (null (setq xx (vl-string-search ":" id)))
    (setq Rtn (list id ""))
    (setq id1 (substr id 1 xx)
   id2 (substr id (+ xx 2))
   id1 (vlxls-rangeid id1)
   id2 (vlxls-rangeid id2)
   Rtn (list (vlxls-rangeid (list (min (car id1) (car id2)) (min (cadr id1) (cadr id2))))
      (vlxls-rangeid (list (max (car id1) (car id2)) (max (cadr id1) (cadr id2))))
       )
    )
  )
  Rtn
)


;;;Examples:
(vlxls-cellid ‘(3 14)) return: ("C14" "")
(vlxls-cellid “D23”) return: ("D23" "")
(vlxls-cellid “C12:F3”) return: ("C3" "F12")
(vlxls-cellid “F15:G22”) return: ("F15" "G22")
回复 支持 0 反对 1

使用道具 举报

 楼主| 发表于 2019-9-14 10:05:50 | 显示全部楼层
ljx-read-excel-data、ljx-read-excel-data、Ljx-vlxls-get-range-value三个函数在收集的大量的函数的支持下运行成功,但这确实显得过于复杂繁琐,多年来自己收集了大量的函数,但换一个人来用就非常不方便,从自己使用的体会来看,越不要外挂,使用系统自带的东西就能运行,越是方便适用,来了点兴趣啊,按以上思路,不依靠那些类型库声明代码、不依靠大量mslx函数和自定义函数就能运行,现基本搞成,在自己的机子上运行良好,以下是经过修改后的函数和运行实例,excel表还是用原来的"ABC.xls"文件啊:
  1. ;;;;;读取excel数据函数
  2. (defun Ljx-read-excel-data1 (vv hor sh) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
  3.   (vlax-variant-value (vlax-get-property (vlax-get-property sh 'Range (strcat vv (itoa hor))) 'Value2))
  4. )

  5. ;;;;;读取excel数据函数输出text格式
  6. (defun Ljx-read-excel-text1 (vv hor sh ) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
  7.   (vl-princ-to-string (vlax-variant-value (vlax-get-property (vlax-get-property sh 'Range (strcat vv (itoa hor))) 'Value2)))
  8. )
  9. ;;;;;;取得单元格数据,支持区域输入
  10. (defun ljx-vlxls-get-range-value1 ( sheet rangeid / range value valuelist )
  11.   (setq range (vlax-get-property sheet 'Range rangeid))
  12.   (setq value (vlax-get-property range 'Value2))
  13.   (cond
  14.     ((= (vlax-variant-type value)  8204);;;为数组时,即为区域;
  15.         (progn
  16.           (setq value (vlax-safearray->list(vlax-variant-value value)))
  17.           (setq valuelist (mapcar (function (lambda (x)  (mapcar 'vlax-variant-value x)  )) value))
  18.         )
  19.     )
  20.     ( T;;;;为单个单元格;
  21.       (setq valuelist (vlax-variant-value value))
  22.     )
  23.   );;;;cond
  24.   valuelist
  25. )

  26. ;;;;运行函数
  27. (defun test1 ()
  28.   (vl-load-com)
  29.   (setq exname "d:\\ABC.xls")
  30.   (setq *excel* (vlax-create-object "excel.application"))
  31.   (setq *xlapp* (vlax-invoke-method (vlax-get-property *excel* 'Workbooks) 'Open exname))
  32.   (vla-put-visible *excel* 1)
  33.   (setq *sheet* (vlax-get-property (vlax-get-property *xlapp* 'Worksheets) 'item "DEF"))
  34.   (setq dat0 (Ljx-vlxls-get-range-value1 *sheet* "E5")
  35.         dat1 (Ljx-vlxls-get-range-value1 *sheet* "E5:F5");;;;输出:((-25.10 "张三"))
  36.         dat2 (Ljx-vlxls-get-range-value1 *sheet* "E5:E6");;;;输出:((-25.10)(26.85))
  37.         dat3 (Ljx-vlxls-get-range-value1 *sheet* "E5:F6");;;;输出:((-25.10 "张三")(26.85 "李四"))
  38.         dat4 (Ljx-read-excel-data1  "E" 5 *sheet*);;;;-->-25.10
  39.         dat5 (Ljx-read-excel-text1  "E"  5  *sheet* );;;;-->"-25.10"
  40.         dat6 (Ljx-read-excel-data1  "E"  6 *sheet* );;;;-->26.85
  41.         dat7 (Ljx-read-excel-text1 "E"  6 *sheet*);;;;-->"26.85"
  42.         dat8 (Ljx-read-excel-data1 "F"  5 *sheet*);;;;-->“张三”
  43.         dat9 (Ljx-read-excel-text1 "F"  5 *sheet*);;;;-->“张三”
  44.         dat10 (Ljx-read-excel-data1  "F"  6 *sheet* );;;;-->"李四"
  45.         dat11 (Ljx-read-excel-text1  "F"  6 *sheet* );;;;-->"李四"
  46.   )
  47.   (vlax-invoke-method (vlax-get-property *excel* "ActiveWorkbook") 'Close 0)
  48.   (vlax-invoke-method *excel* 'QUIT)
  49.   (vlax-release-object *sheet*)
  50.   (vlax-release-object *xlapp*)
  51. )
  52. ;;;;具体使用时先将ABC.xls(解压ABC.zip)拷贝至d盘根目录下,加载test1.lsp文件,在CAD命令行输入 (test1)即可运行

本帖子中包含更多资源

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

x
 楼主| 发表于 2019-9-7 19:47:47 | 显示全部楼层
再贴一个我用的函数,一般读取excel数据基本够用了啊:
取得exce表指定单元格数据:
  1. ;;;;;;Ljx-vlxls-get-range-value
  2. ;;;;;;取得单元格数据,支持区域输入
  3. ;;;;;;参数:sheet当前工作表,rangeid:区域id,如"A1","A1:F10", "A1:A100","A1:EE1"
  4. ;;;;;;示例:(Ljx-vlxls-get-range-value *sheet* "E5")输出:-25.10,
  5. ;;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:F5"")输出:((-25.10 "张三"))
  6. ;;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:E6"")输出:((-25.10)(26.85))
  7. ;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:F6"")输出:((-25.10 "张三")(26.85 "李四")
  8. (defun Ljx-vlxls-get-range-value (sheet rangeid / range value value1 valuelist index_i)
  9.   (setq range (msxl-get-range sheet rangeid))
  10.   (setq value (MSXL-GET-VALUE2 range ))
  11.   (cond
  12.     ((=(vlax-variant-type value)  8204);;;为数组时,即为区域
  13.      (progn
  14.        (setq value (vlax-safearray->list(vlax-variant-value value)))
  15.        (setq valuelist '()
  16.              index_i 0
  17.        )
  18.        (repeat (length value)
  19. (setq value1 (nth index_i value))
  20. (setq valuelist (cons (mapcar
  21.      '(lambda (x)(vlax-variant-value x))
  22.      value1
  23.        )
  24.        valuelist
  25. )
  26. )
  27. (setq index_i (1+ index_i))
  28.        );;;;repeat
  29.        (setq valuelist (reverse valuelist))
  30.      )
  31.     )
  32.     (T;;;;为单个单元格
  33.      (setq valuelist (vlax-variant-value value))
  34.     )
  35.   );;;;cond
  36.   valuelist
  37. );;;;defun

发表于 2019-9-8 09:13:41 | 显示全部楼层
留个脚印,先
发表于 2019-9-8 15:13:59 | 显示全部楼层
(Ljx-vlxls-get-range-value *sheet* "E5:F5"")
*sheet*具体些,或具体实例,好让新手明白

  1. (defun Ljx-read-excel-data (vv hor sh / hor ru)
  2. (defun Ljx-read-excel-text (vv hor sh / hor ru)
  3. ;;;sh;具体些,或具体实例,好让新手明白

 楼主| 发表于 2019-9-8 18:21:01 | 显示全部楼层
crtrccrt说的很对,*SHeet*、sh均为工作表对象,就是你要读取数据的工作表,VV和hor分开主要便于循环读取,Ljx-vlxls-get-range-value函数功能强一些,当为单个单元格时如(Ljx-vlxls-get-range-value *sheet* "E5")直接读得该单元格的数据,输出:-25.10,为区域时按((第一行) (第二行)...(第n行))的格式读取输出,
  1. ;;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:F5")输出:((-25.10 "张三")),第5行:“E5”数据为-25.10、“F5”数据为“张三”
  2. ;;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:E6")输出:((-25.10)(26.85)) ,第5行“E5”数据为-25.10、第六行“E6”数据为26.85
  3. ;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:F6")输出:((-25.10 "张三")(26.85 "李四")),第五行:“E5”数据为-25.10、“F5”数据为“张三”;第六行:“E6”数据为26.85、 “F6”数据为"李四"。
  4. 简单点,几个单元格数据分别为:
  5. "E5"=-25.10
  6. "F5"=“张三”
  7. "E6"=26.85
  8. "F6"=“李四”。
  9. (Ljx-read-excel-data  "E"  5 *sheet*)-->-25.10
  10. (Ljx-read-excel-text  "E"  5  *sheet* )-->"-25.10"
  11. (Ljx-read-excel-data  "E"  6 *sheet* )-->26.85
  12. (Ljx-read-excel-text "E"  6 *sheet*)-->"26.85"

  13. (Ljx-read-excel-data "F"  5 *sheet*)-->“张三”
  14. (Ljx-read-excel-text "F"  5 *sheet*)-->“张三”
  15. (Ljx-read-excel-data  "F"  6 *sheet* )-->"李四"
  16. (Ljx-read-excel-text  "F"  6 *sheet* )-->"李四"

  17. ;;;;两个函数再精简一下:
  18. ;;;;;读取excel数据函数
  19. (defun Ljx-read-excel-data (vv hor sh /  ru) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
  20.   (setq ru (vlax-variant-value (msxl-get-value (msxl-get-range sh (strcat vv (itoa hor))))))
  21. )

  22. ;;;;;读取excel数据函数输出text格式
  23. (defun Ljx-read-excel-text (vv hor sh /  ru) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
  24.   (setq ru (vlax-variant-value (msxl-get-text (msxl-get-range sh (strcat vv (itoa hor))))))
  25. )

  26. ;;;;这样好像差不多了,这几个函数都是在初始化excel应用程序,打开excel表格,取得要读取的sheet后才能用啊,有关的步骤论坛上都有,大家可以去搜索一下




发表于 2019-9-9 21:04:54 | 显示全部楼层
举例:
d:/ABC.xls中有DEF工作簿
如何形成Ljx-vlxls-get-range-value子程序需要的*sheet*参数.
新手一时半会也搞不明白.
直接给新手实例,举手之劳,新手会节省很多时间.
 楼主| 发表于 2019-9-10 10:28:22 | 显示全部楼层
本帖最后由 ljxkm 于 2019-9-10 20:37 编辑
crtrccrt 发表于 2019-9-9 21:04
举例:
d:/ABC.xls中有DEF工作簿
如何形成Ljx-vlxls-get-range-value子程序需要的*sheet*参数.

这有点超出贴两个函数源码的初衷了啊,真要函数动起来,还需要不少步骤,用到不少函数哈,不过既然提出来,就啰嗦一下,用到的函数都是网路搜索的集体成果啊:
定义以下函数:
(defun test ()
  (vl-load-com)
  (setq exname "d:\\ABC.xls")
  (vlxls-app-init1 exname)
  (setq *xlapp* (vlxls-app-open exname T))
  (vlxls-sheet-put-active *xlapp* "DEF");;;;设为活动工作表
  (setq *sheet* (msxl-get-ActiveSheet *Xlapp*))
  (setq dat0 (Ljx-vlxls-get-range-value *sheet* "E5")
        dat1 (Ljx-vlxls-get-range-value *sheet* "E5:F5");;;;输出:((-25.10 "张三"))
        dat2 (Ljx-vlxls-get-range-value *sheet* "E5:E6");;;;输出:((-25.10)(26.85))
        dat3 (Ljx-vlxls-get-range-value *sheet* "E5:F6");;;;输出:((-25.10 "张三")(26.85 "李四"))
        dat4 (Ljx-read-excel-data  "E" 5 *sheet*);;;;-->-25.10
        dat5 (Ljx-read-excel-text  "E"  5  *sheet* );;;;-->"-25.10"
        dat6 (Ljx-read-excel-data  "E"  6 *sheet* );;;;-->26.85
        dat7 (Ljx-read-excel-text "E"  6 *sheet*);;;;-->"26.85"
        dat8 (Ljx-read-excel-data "F"  5 *sheet*);;;;-->“张三”
        dat9 (Ljx-read-excel-text "F"  5 *sheet*);;;;-->“张三”
        dat10 (Ljx-read-excel-data  "F"  6 *sheet* );;;;-->"李四"
        dat11 (Ljx-read-excel-text  "F"  6 *sheet* );;;;-->"李四"
  )  
  (vlxls-app-quit *xlapp* nil);;;;退出excel应用程序  
  (vlax-Release-Object *sheet*)
)
;;;;具体使用时先将ABC.xls(解压ABC.zip)拷贝至d盘根目录下,加载test.lsp文件,在CAD命令行输入 (test)即可运行,好了,两个函数扯出这么多来,lisp操控excel有点复杂,是集体智慧,实际工作中,要收集前辈编的较为全面的函数拷在一个lsp文件下成为模块,这样就方便了,excel版本不断更新,以前在网络上找的vlxls-app-init函数不能用了,那个vlxls-app-init1是我自己改来用的,一并贴出了,有点啰嗦,不是很好,但确实是可用的,祝大家进步,提高





本帖子中包含更多资源

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

x

评分

参与人数 1明经币 +1 收起 理由
USER2128 + 1 赞一个!

查看全部评分

发表于 2019-9-11 11:31:13 | 显示全部楼层
;=========楼主细心,认真,值得表扬。;
;=========优化后Ljx-vlxls-get-range-value;
;;;;;;Ljx-vlxls-get-range-value
;;;;;;取得单元格数据,支持区域输入
;;;;;;参数:sheet当前工作表,rangeid:区域id,如"A1","A1:F10", "A1:A100","A1:EE1"
;;;;;;示例:(Ljx-vlxls-get-range-value *sheet* "E5");;;;;输出:-25.10,
;;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:F5");输出:((-25.10 "张三"))
;;;;;;      (Ljx-vlxls-get-range-value *sheet* "E5:E6");输出:((-25.10)(26.85))
;;;;;       (Ljx-vlxls-get-range-value *sheet* "E5:F6");输出:((-25.10 "张三")(26.85 "李四")
(defun ljx-vlxls-get-range-value ( sheet rangeid / range value valuelist )
  (setq range (msxl-get-range sheet rangeid))
  (setq value (MSXL-GET-VALUE2 range ))
  (cond
    ( (= (vlax-variant-type value)  8204);;;为数组时,即为区域;
        (progn
          (setq value (vlax-safearray->list(vlax-variant-value value)))
          (setq valuelist (mapcar (function (lambda (x)  (mapcar 'vlax-variant-value x)  )) value))
        )
    )
    ( T;;;;为单个单元格;
      (setq valuelist (vlax-variant-value value))
    )
  );;;;cond
  valuelist
)
 楼主| 发表于 2019-9-11 13:02:26 | 显示全部楼层
crtrccrt 发表于 2019-9-11 11:31
;=========楼主细心,认真,值得表扬。;
;=========优化后Ljx-vlxls-get-range-value;
;;;;;;Ljx-vlxls ...

这样确实简洁,mapcar这个函数确实好,
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-13 14:37 , Processed in 0.194725 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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