用 Lisp 对 INI 文件解析

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/yxp_xa/article/details/72539877

当你不想用 DCL 来交互程序的参数设置时,读取 ini 配置文件可以作为一个备用选择,也能方便用户修改。
AutoLISP 程序设计时常用的数据存储方式,各有优缺点:
1. 非图形对象数据字典
2. Windows 注册表
3. 磁盘文件
第一种方式,程序参数将随 DWG 图一起存储,当新开一个图形后,参数需要重新配置
第二种方式,不符合绿色软件的原则,不适合保存大量数据,如对象 DXF 码。有时候会被杀毒软件屏蔽。
第三种方式,LISP 找不到自己加载的路径,无法将参数文件和程序放在同一目录里

本程序为磁盘存储方式提供了统一接口,可以不设置路径,程序将在支持目录里搜索。
例如下面代码将保存一个对象的 dxf 码到ini文件,文件与当前 dwg 同路径。

(setq ss (strcat (getvar "DWGPREFIX") (getvar "DWGNAME") ".ini"))
(vl-ini-set (list ss "LIST表" "DXF" (entget(car(entsel)))))

如果需要读出刚刚保存的 dxf 数据

(vl-ini-get (list ss "LIST表" "DXF"))

程序源代码如下:

用 Lisp 对 INI 文件解析 
版权所有 (c)  by.  yxp  QQ:9034598   2015-08-16   明经通道
转载或引用,请注明作者和出处

功能:读取磁盘配置文件
语法: (vl-ini-get ini-list)
参数: ini-list 为表类型
ini-list = (inifile [section [key [default]]])
    inifile 指定的INI文件
    section INI文件中的段落
    key INI文件中的关键字
    default 若INI文件中没有关键字则默认返回值
返回值:
    1、只含 INI文件 则返回所有段落名称
    2、含 section 则返回指定段落下的所有关键字
    3、含 key 则返回指定段落下的指定关键字的值,失败则返回 nil
    4、含 default 则返回指定段落下的指定关键字的值,失败则返回 default
示例: (vl-ini-get "CAD.ini")


(vl-load-com)

;;配置文件类别,大写,程序运行过程中可修改, 如
;;(setq yxp_file_ext_key "*.TXT")
(setq yxp_file_ext_key "*.INI")

;;依赖顺序进行参数合法性判断  vl-ini-get
;;子函数3个: yxp_read_ini  yxp_read_sec  yxp_read_key
(defun vl-ini-get( ini-list / )
    (cond
        ;;转到帮助
        ((or (= ini-list '?)(= ini-list "?"))(vl-ini-get-help)(princ))
        ;;判断参数是否表类型
        ((/= (type ini-list) 'List)(princ "\n; 错误: 要求表参数")(princ))
        ;;判断参数数量
        ((> (length ini-list) 4)(princ "\n; 错误: 表参数太多")(princ))
        ;;判断第一个表参数是否字符型
        ((/= (type (car ini-list)) 'Str)(princ "\n; 错误: 要求字符型参数")(princ))
        ;;判断文件名是否 yxp_file_ext_key 类型
        ((null (wcmatch (strcase (car ini-list)) yxp_file_ext_key))
            (princ (strcat "\n; 错误: 不是有效的 " yxp_file_ext_key " 文件名"))(princ))
        ;;路径长度限制
        ((> (strlen (car ini-list)) 256)(princ "\n; 错误: 路径及文件名长度超限")(princ))
        ;;判断第一个参数是否路径
        ((null (findfile (car ini-list)))(princ "\n; 错误: 不能读取的路径或文件名称")(princ))
        ;;第二个参数不存在,则返回 ini 文件所有段落名
        ((null (cadr ini-list))(yxp_read_ini (car ini-list)))
        ;;判断第二个参数是否字符型
        ((/= (type (cadr ini-list)) 'Str)(princ "\n; 错误: 段落名称类型不正确")(princ))
        ;;判断段落名称是否合法,不能为空字符
        ((wcmatch (cadr ini-list) " ")(princ "\n; 错误: 段落名称不合法")(princ))
        ;;段落字符长度限制
        ((> (strlen (cadr ini-list)) 64)(princ "\n; 错误: 段落长度超限")(princ))
        ;;第三个参数不存在,则返回段落名下所有关键字
        ((null (caddr ini-list))(yxp_read_sec ini-list))
        ;;判断关键字是否字符型
        ((/= (type (caddr ini-list)) 'Str)(princ "\n; 错误: 关键字类型不正确")(princ))
        ;;关键字是否合法,不能包含 = ,不能是空格
        ((wcmatch (caddr ini-list) "*=*, ")(princ "\n; 错误: 关键字不合法")(princ))
        ;;关键字长度限制
        ((> (strlen (caddr ini-list)) 64)(princ "\n; 错误: 关键字长度超限")(princ))
        ;;返回关键字的值
        (t (yxp_read_key ini-list))
    )
)

;;返回所有段落名。 ss 文件名
(defun yxp_read_ini (ss / fn xx rowini)
    (setq fn (open (findfile ss) "r"))
    (while (setq xx (read-line fn))
        (if (wcmatch xx "`[*`]")(setq rowini (cons (vl-string-trim "[ ]" xx) rowini)))
    )
    (close fn)
    (reverse (vl-remove "" rowini)) ;;剔除空段落
)

;;返回指定段落的关键字列表。 ss 表: 文件名、段落
(defun yxp_read_sec(ss / fname sec fn xx FLAG secrow rows nn)
    (setq fname (car ss)  ;;文件名
        sec (vl-string-trim " " (cadr ss))  ;;段落,删除前后空格
        fn (open (findfile fname) "r"))
    (while (setq xx (read-line fn))
        (if (wcmatch xx "`[*`]") ;;匹配段落
            (setq FLAG (= (vl-string-trim "[ ]" xx) sec))
        )  ;;搜到段落时 FLAG=T,开始记录关键字。
        (if FLAG (setq rows (cons xx rows))) ;;读出指定段落的关键字
    )(close fn)
    (setq rows (cdr (reverse rows))) ;;删除第一行段落名,只留关键字
    (while (setq xx (car rows))
        (setq rows (cdr rows)
            nn (vl-string-search "=" xx))  ;;关键字不合法时 nn=nil
        (if nn (setq xx (vl-string-trim " " (substr xx 1 nn))
                secrow (cons xx secrow)))
    ) (reverse secrow)
)

;;返回指定关键字的值。 ss 表: 文件名、段落名、关键字、值
(defun yxp_read_key (ss / fname sec fn xx secrow rows nn)
    (setq fname (car ss)
        sec (vl-string-trim " " (cadr ss))
        key (vl-string-trim " " (caddr ss)) ;;关键字,删除前后空格
        fn (open (findfile fname) "r"))
    (while (setq xx (read-line fn))
        (if (wcmatch xx "`[*`]") 
            (setq FLAG (= (vl-string-trim "[ ]" xx) sec))
        )
        (if FLAG (setq rows (cons xx rows)))
    )(close fn)
    (setq rows (cdr (reverse rows)))
    (while (setq xx (car rows))
        (setq rows (cdr rows)
            nn (vl-string-search "=" xx))  ;;此前与 yxp_read_sec 函数相同
        (if nn (setq secrow (cons (list (vl-string-trim " " (substr xx 1 nn)) (vl-string-trim " " (substr xx (+ 2 nn)))) secrow)))
    ) 
    (setq ff (cadr (assoc key (reverse secrow))))
    (if ff ff (cadddr ss))
)

;;参数合法性判断  vl-ini-set
;;子函数 1 个:  yxp_save_ini
(defun vl-ini-set( ini-list )
    (cond
        ;;转到帮助
        ((or (= ini-list '?)(= ini-list "?"))(vl-ini-set-help)(princ))
        ;;判断参数是否表类型
        ((/= (type ini-list) 'List)(princ "\n; 错误: 要求表参数")(princ))
        ;;判断参数数量
        ((or (< (length ini-list) 2)(> (length ini-list) 4))
            (princ "\n; 错误: 表参数不足或太多")(princ))
        ;;判断第一个表参数是否字符型
        ((/= (type (car ini-list)) 'Str)(princ "\n; 错误: 要求字符型参数")(princ))
        ;;判断文件名是否 yxp_file_ext_key 类型
        ((null (wcmatch (strcase (car ini-list)) yxp_file_ext_key))
            (princ (strcat "\n; 错误: 不是有效的 " yxp_file_ext_key " 文件名"))(princ))
        ;;判断段落名是否字符型
        ((/= (type (cadr ini-list)) 'Str)(princ "\n; 错误: 段落名称类型不正确")(princ))
        ;;判断段落名称是否合法,不能为空字符
        ((wcmatch (cadr ini-list) " ")(princ "\n; 错误: 段落名称不合法")(princ))
        ;;判断第三个参数是否字符型
        ((and (caddr ini-list)(/= (type (caddr ini-list)) 'Str))
            (princ "\n; 错误: 关键字类型不正确")(princ))
        ;;判断关键字是否合法,不能为空字符
        ((and (caddr ini-list)(wcmatch (caddr ini-list) " "))
            (princ "\n; 错误: 关键字不合法")(princ))
        ;;前三个参数的字长限制
        ((or (> (strlen (car ini-list)) 256)(> (strlen (cadr ini-list)) 64)
            (and (caddr ini-list) (> (strlen (caddr ini-list)) 64)))
            (princ "\n; 错误: 参数字符长度超限")(princ))
        ;;如果第三个参数不存在,则保存段落名
        (t (yxp_save_ini ini-list))
    )
)

;; 读入 ini ,如果不存在,则创建, 如果存在,则修改
;; 算法:从后往前搜索段落名,找到后再从前往后搜索关键字
(defun yxp_save_ini (ss / C wc A B seq qq fa FLAG r1 r2 fb AA)
    (setq fa (open (car ss) "r")
        sec (vl-string-trim " " (cadr ss)))
    (if (caddr ss)
        (setq key (vl-string-trim " " (caddr ss))
            qq (strcat key " = ")
            wc (strcat key "=*," key " =*")))
    (if (cadddr ss)(setq qq (strcat qq (vl-princ-to-string (cadddr ss)))))  
    (if fa (progn
        (while (setq xx (read-line fa))(setq A (cons xx A)))
        (close fa)
        (setq AA A)
        (if (caddr ss)(progn (while (setq r1 (car A)) (if (wcmatch (vl-string-trim " " r1) wc)(setq FLAG t)) (if (wcmatch r1 "`[*`]") (if (= (vl-string-trim "[ ]" r1) sec) (progn (if FLAG (progn (setq r2 (car B)) (while (null (wcmatch (vl-string-trim " " r2) wc)) (setq A (cons r2 A) B (cdr B) r2 (car B)) ) (setq C (append (reverse A) (cons qq (cdr B)))) ) (setq C (append (reverse A) (cons qq B))) ) (setq A nil)) (setq FLAG nil) ) ) (setq B (cons r1 B) A (cdr A)) ) ;; the end (if (null C)(setq C (cons (strcat "[" sec "]") (cons qq B)))) )(progn (while (setq r1 (car A)) (if (and (wcmatch r1 "`[*`]") (= (vl-string-trim "[ ]" r1) sec)) (setq A nil B nil) (setq B (cons r1 B) A (cdr A)) ) ) (setq C (if B (cons (strcat "[" sec "]") B))) )
        )
        (if (null AA)
            (if (caddr ss) (setq C (list (strcat "[" sec "]") qq)) (setq C (list (strcat "[" sec "]"))))
        ))
        (setq C (list (strcat "[" sec "]") (if qq qq "")))
    )
    (if C (progn
        (setq fb (open (car ss) "w"))
        (foreach x C (write-line x fb))
        (close fb)
        (if (= 3 (length ss)) "" (last ss))
    ))
)

(defun vl-ini-set-help()
(princ (strcat "\n"
    "功能: 保存 ini 配置文件, 程序编写: yxp  2015-8-16" "\n"
    "语法: (vl-ini-set ini-list)" "\n"
    "参数: ini-list == (inifile section [key [value]])" "\n"
    "  inifile   必选, 字符型, 路径 + 文件名" "\n"
    "  section   必选, 字符型, 段落名, 长度不大于 64" "\n"
    "  key       可选, 字符型, 关键字, 长度不大于 64, 未设置时只保存段落" "\n"
    "  value     可选, 任意类型, 关键字的值, 长度不限, 未设置时关键字为空字符" "\n"
    "返回值: 失败时返回 nil, 成功则返回保存的数据" "\n"
))
)

(defun vl-ini-get-help()
(princ (strcat "\n"
    "功能: 读入 ini 配置文件, 程序编写: yxp  2015-8-16" "\n"
    "语法: (vl-ini-get ini-list)" "\n"
    "参数: ini-list == (inifile [section [key [default]]])" "\n"
    "  inifile   必选, 字符型, 路径 + 文件名" "\n"
    "  section   可选, 字符型, 段落名, 长度不大于 64" "\n"
    "  key       可选, 字符型, 关键字, 长度不大于 64" "\n"
    "  default   可选, 任意类型, 关键字的值, 长度不限" "\n"
    "返回值:" "\n"
    "  1、只含 inifile 返回所有段落名称" "\n"
    "  2、仅含 section 返回指定段落下的所有关键字" "\n"
    "  3、仅含 key 返回指定关键字的值,未找到关键字则返回 nil" "\n"
    "  4、含 default 返回指定关键字的值,未找到则返回 default" "\n"
))
)
(princ)

猜你喜欢

转载自blog.csdn.net/yxp_xa/article/details/72539877
今日推荐