两个简单的读取excel表格函数
在CAD二次开发中,常需要读取excel表格数据,根据lisp语言的特点,有时一个一个单元格读取反而方便,以下是在实际中常用的两个读取excel表格数据小程序,个人觉得还是比较实用啊:;;;;;读取excel据函数
(defun Ljx-read-excel-data (vv hor sh / hor ru) ;;;vv为列数直接输入字母、hor为行数,直接输入数字,sh为工作表对象sheet
(setq hor (itoa hor))
(setq ru (vlax-variant-value (msxl-get-value (msxl-get-range sh (strcat vv hor)))))
ru
)
;;;;;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
;;;;;读取excel数据函数输出text格式
(defun Ljx-read-excel-text (vv hor sh / hor ru) ;;;vv为列数直接输入字母、hor为行数,直接输入数字,sh为工作表对象sheet
(setq hor (itoa hor))
(setq ru (vlax-variant-value (msxl-get-text (msxl-get-range sh (strcat vv hor)))))
ru
)
;;;ljx-vlxls-app-Init;子程序局部优化;
(cond
( (wcmatch excelname "*.xls");;;为2003-xls文件时;
(cond
( (setq out2003 (vl-member-if (function (lambda (x) (findfile x))) hm-2003)) (setq out (car out2003)) )
( (setq out2007 (vl-member-if (function (lambda (x) (findfile x))) hm-2007)) (setq out (car out2007)) )
( (setq out2010 (vl-member-if (function (lambda (x) (findfile x))) hm-2010)) (setq out (car out2010)) )
( (setq out2013 (vl-member-if (function (lambda (x) (findfile x))) hm-2013)) (setq out (car out2013)) )
( (setq out2016 (vl-member-if (function (lambda (x) (findfile x))) hm-2016)) (setq out (car out2016)) )
( t (princ "\\n计算机上未安装excel2003、excel2007、excel2010、excel2013、excel2016,不能打开xls文件!"))
);;;cond;
)
( (wcmatch excelname "*.xlsx");;;为2007-xlsx文件时;
(cond
( (setq out2007 (vl-member-if (function (lambda (x) (findfile x))) hm-2007)) (setq out (car out2007)) )
( (setq out2010 (vl-member-if (function (lambda (x) (findfile x))) hm-2010)) (setq out (car out2010)) )
( (setq out2013 (vl-member-if (function (lambda (x) (findfile x))) hm-2013)) (setq out (car out2013)) )
( (setq out2016 (vl-member-if (function (lambda (x) (findfile x))) hm-2016)) (setq out (car out2016)) )
( t (princ "\\n计算机上未安装excel2007、excel2010、excel2013、excel2016,不能打开xls文件!"))
);;;cond;
)
( T(setq out nil))
);;;cond;
;;;先加载低版本,低版本不存在再加载高版本;;
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")
ljx-read-excel-data、ljx-read-excel-data、Ljx-vlxls-get-range-value三个函数在收集的大量的函数的支持下运行成功,但这确实显得过于复杂繁琐,多年来自己收集了大量的函数,但换一个人来用就非常不方便,从自己使用的体会来看,越不要外挂,使用系统自带的东西就能运行,越是方便适用,来了点兴趣啊,按以上思路,不依靠那些类型库声明代码、不依靠大量mslx函数和自定义函数就能运行,现基本搞成,在自己的机子上运行良好,以下是经过修改后的函数和运行实例,excel表还是用原来的"ABC.xls"文件啊:
;;;;;读取excel数据函数
(defun Ljx-read-excel-data1 (vv hor sh) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
(vlax-variant-value (vlax-get-property (vlax-get-property sh 'Range (strcat vv (itoa hor))) 'Value2))
)
;;;;;读取excel数据函数输出text格式
(defun Ljx-read-excel-text1 (vv hor sh ) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
(vl-princ-to-string (vlax-variant-value (vlax-get-property (vlax-get-property sh 'Range (strcat vv (itoa hor))) 'Value2)))
)
;;;;;;取得单元格数据,支持区域输入
(defun ljx-vlxls-get-range-value1 ( sheet rangeid / range value valuelist )
(setq range (vlax-get-property sheet 'Range rangeid))
(setq value (vlax-get-property range 'Value2))
(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
)
;;;;运行函数
(defun test1 ()
(vl-load-com)
(setq exname "d:\\ABC.xls")
(setq *excel* (vlax-create-object "excel.application"))
(setq *xlapp* (vlax-invoke-method (vlax-get-property *excel* 'Workbooks) 'Open exname))
(vla-put-visible *excel* 1)
(setq *sheet* (vlax-get-property (vlax-get-property *xlapp* 'Worksheets) 'item "DEF"))
(setq dat0 (Ljx-vlxls-get-range-value1 *sheet* "E5")
dat1 (Ljx-vlxls-get-range-value1 *sheet* "E5:F5");;;;输出:((-25.10 "张三"))
dat2 (Ljx-vlxls-get-range-value1 *sheet* "E5:E6");;;;输出:((-25.10)(26.85))
dat3 (Ljx-vlxls-get-range-value1 *sheet* "E5:F6");;;;输出:((-25.10 "张三")(26.85 "李四"))
dat4 (Ljx-read-excel-data1"E" 5 *sheet*);;;;-->-25.10
dat5 (Ljx-read-excel-text1"E"5*sheet* );;;;-->"-25.10"
dat6 (Ljx-read-excel-data1"E"6 *sheet* );;;;-->26.85
dat7 (Ljx-read-excel-text1 "E"6 *sheet*);;;;-->"26.85"
dat8 (Ljx-read-excel-data1 "F"5 *sheet*);;;;-->“张三”
dat9 (Ljx-read-excel-text1 "F"5 *sheet*);;;;-->“张三”
dat10 (Ljx-read-excel-data1"F"6 *sheet* );;;;-->"李四"
dat11 (Ljx-read-excel-text1"F"6 *sheet* );;;;-->"李四"
)
(vlax-invoke-method (vlax-get-property *excel* "ActiveWorkbook") 'Close 0)
(vlax-invoke-method *excel* 'QUIT)
(vlax-release-object *sheet*)
(vlax-release-object *xlapp*)
)
;;;;具体使用时先将ABC.xls(解压ABC.zip)拷贝至d盘根目录下,加载test1.lsp文件,在CAD命令行输入 (test1)即可运行
再贴一个我用的函数,一般读取excel数据基本够用了啊:
取得exce表指定单元格数据:
;;;;;;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 value1 valuelist index_i)
(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 '()
index_i 0
)
(repeat (length value)
(setq value1 (nth index_i value))
(setq valuelist (cons (mapcar
'(lambda (x)(vlax-variant-value x))
value1
)
valuelist
)
)
(setq index_i (1+ index_i))
);;;;repeat
(setq valuelist (reverse valuelist))
)
)
(T;;;;为单个单元格
(setq valuelist (vlax-variant-value value))
)
);;;;cond
valuelist
);;;;defun
留个脚印,先 (Ljx-vlxls-get-range-value *sheet* "E5:F5"")
*sheet*具体些,或具体实例,好让新手明白
(defun Ljx-read-excel-data (vv hor sh / hor ru)
(defun Ljx-read-excel-text (vv hor sh / hor ru)
;;;sh;具体些,或具体实例,好让新手明白
crtrccrt说的很对,*SHeet*、sh均为工作表对象,就是你要读取数据的工作表,VV和hor分开主要便于循环读取,Ljx-vlxls-get-range-value函数功能强一些,当为单个单元格时如(Ljx-vlxls-get-range-value *sheet* "E5")直接读得该单元格的数据,输出:-25.10,为区域时按((第一行) (第二行)...(第n行))的格式读取输出,
;;;;;; (Ljx-vlxls-get-range-value *sheet* "E5:F5")输出:((-25.10 "张三")),第5行:“E5”数据为-25.10、“F5”数据为“张三”
;;;;;; (Ljx-vlxls-get-range-value *sheet* "E5:E6")输出:((-25.10)(26.85)) ,第5行“E5”数据为-25.10、第六行“E6”数据为26.85
;;;;; (Ljx-vlxls-get-range-value *sheet* "E5:F6")输出:((-25.10 "张三")(26.85 "李四")),第五行:“E5”数据为-25.10、“F5”数据为“张三”;第六行:“E6”数据为26.85、 “F6”数据为"李四"。
简单点,几个单元格数据分别为:
"E5"=-25.10
"F5"=“张三”
"E6"=26.85
"F6"=“李四”。
(Ljx-read-excel-data"E"5 *sheet*)-->-25.10
(Ljx-read-excel-text"E"5*sheet* )-->"-25.10"
(Ljx-read-excel-data"E"6 *sheet* )-->26.85
(Ljx-read-excel-text "E"6 *sheet*)-->"26.85"
(Ljx-read-excel-data "F"5 *sheet*)-->“张三”
(Ljx-read-excel-text "F"5 *sheet*)-->“张三”
(Ljx-read-excel-data"F"6 *sheet* )-->"李四"
(Ljx-read-excel-text"F"6 *sheet* )-->"李四"
;;;;两个函数再精简一下:
;;;;;读取excel数据函数
(defun Ljx-read-excel-data (vv hor sh /ru) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
(setq ru (vlax-variant-value (msxl-get-value (msxl-get-range sh (strcat vv (itoa hor))))))
)
;;;;;读取excel数据函数输出text格式
(defun Ljx-read-excel-text (vv hor sh /ru) ;;;vv为列数直接输入字母、hor为 第几行,直接输入数字,sh为工作表对象sheet
(setq ru (vlax-variant-value (msxl-get-text (msxl-get-range sh (strcat vv (itoa hor))))))
)
;;;;这样好像差不多了,这几个函数都是在初始化excel应用程序,打开excel表格,取得要读取的sheet后才能用啊,有关的步骤论坛上都有,大家可以去搜索一下
举例:
d:/ABC.xls中有DEF工作簿
如何形成Ljx-vlxls-get-range-value子程序需要的*sheet*参数.
新手一时半会也搞不明白.
直接给新手实例,举手之劳,新手会节省很多时间.
本帖最后由 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是我自己改来用的,一并贴出了,有点啰嗦,不是很好,但确实是可用的,祝大家进步,提高
;=========楼主细心,认真,值得表扬。;
;=========优化后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
) crtrccrt 发表于 2019-9-11 11:31
;=========楼主细心,认真,值得表扬。;
;=========优化后Ljx-vlxls-get-range-value;
;;;;;;Ljx-vlxls ...
这样确实简洁,mapcar这个函数确实好,