Lisp 语言中 split 的实现方法与效率
来源:互联网 发布:js求字符串字节长度 编辑:程序博客网 时间:2024/05/17 22:57
在字符串处理中,各种高级语言均支持 split 函数,比如 vb、C#、Python、java 等,split 的基本功能是用一个短字符串去分割一个长字符串,并返回分割后的数组。
例如: (split "I Love You" " ")
用空格切割字符串,返回 ("I" "Love" "You")
遗憾的是 Lisp 中并未包括此函数,本文将讨论 split 在 lisp 语言中的实现方法与效率。
自定义函数
以下两个函数分别是明经和小东论坛里,大师们用 VLisp 函数实现的 split 方法
其中参数为: str — 待处理的长字符串; p — 为分割关键词
;;来自明经,该函数使用频率较高,互相引用频繁,原作者不详(defun Split1 (str p / pa sl xn)(setq xn (1+ (strlen p)))(while (setq pa (vl-string-search p str)) (setq sl (cons (substr str 1 pa) sl) str (substr str (+ pa xn))))(reverse (cons str sl)))
;;来自小东, Gu_xl 的 vlstring->list(Defun Split2 (str p / lst e)(setq str (strcat str p))(while (vl-string-search p str) (setq lst (append lst (list (substr str 1 (vl-string-search p str))))) (setq str (substr str (+ (1+ (strlen p)) (vl-string-search p str)))))(if lst (mapcar '(lambda (e) (vl-string-trim " " e)) lst)))
以上函数算法基本相同:即用 vl-string-search 函数搜索 p 在 str 中出现的位置,再用 substr 按位置切割 str 字符串,并将返回值重新组合为一个 list 表。
测试:
命令: (split1 “I Love You” ” “) 返回 (“I” “Love” “You”)
命令: (split2 “I Love You” ” “) 返回 (“I” “Love” “You”)
如果到这里结束的话,就属于灌水的博客,显然本文的目的并不在此。再看下面出现汉字时的调用:
命令: (Split1 “粃糠abczyx” “z”) 返回 (“? “糠abc” “yx”)
命令: (Split2 “笨賊a\shit” “\”) 返回 (“笨? “a” “shit”)
返回值出现 bug,说明函数对字符的处理有漏洞。
修正 SPLIT
经测试,上面函数 bug 出现原因是 vl-string-search 函数造成的。
该函数在处理英文字符时,按一个字节 ascii 码搜索,处理汉字时,是按两个字节的 ascii 码,而不是将汉字视为一个整体。
命令: (vl-string->list “z”) 返回 (122)
命令: (vl-string->list “粃”) 返回 (187 122)
当函数的参数 str 里的汉字出现了参数 p 中英文字符的 ascii 码时,字符分割就会出现问题。
根据这个现象,增加对汉字的判断,如果首字节 ASCII 大于 128 时,即为汉字,则跳过两个字节。修正后的 split 函数如下:
(defun Split3 (str p / pa sl xn f)(setq xn (1+ (strlen p)) f 0)(while (setq pa (vl-string-search p str f)) (if (< (vl-string-elt str (1- pa)) 128) (setq sl (cons (substr str 1 pa) sl) str (substr str (+ pa xn)) f 0) (setq f (1+ pa)) ))(reverse (cons str sl)))
正则 SPLIT
关于 AutoCAD 以及自带的 LISP 语言对中文字符处理的先天性缺陷,在其他语言中很少存在,现用正则表达式来设计一个 split 函数:
(defun Split (s p / L r)(setq r (vlax-create-object "vbscript.regexp"))(vlax-put-property r 'Global 1)(vlax-put-property r 'Pattern (strcat "([^" p "]+)"))(vlax-for x (vlax-invoke r 'Execute s)(setq L (cons(vla-get-Value x) L)))(vlax-release-object r)(reverse L))
用正则很简洁,只需要告诉正则对象的匹配语法即可。而且这个函数还有一个实用的功能,可以支持多个关键字分割,只需要用 “|”将关键字分开即可。
测试:
命令: (Split “粃糠abczyx” “z”) 返回 (“粃糠abc” “yx”)
命令: (split “abcfarecadefge” “c|f”) 返回 (“ab” “are” “ade” “ge”)
效率测试
创建一个长度为十万的字符串,对比测试一下 vlisp 和 正则 函数的分割效率。
(defun c:test( / i AA)(setq i 0 AA "")(while (< i 100000) (setq AA (strcat AA (itoa (setq i (1+ i))) ",")))(setq time0 (getvar "date"))(Split3 AA ",") ;;调用 VL 函数(setq time1 (getvar "date"))(Split AA ",") ;;调用正则函数(setq time2 (getvar "date"))(princ (strcat "\nVLisp函数耗时: " (rtos (* 86400 (- time1 time0)) 2 4) " 秒"))(princ (strcat "\n正则函数耗时: " (rtos (* 86400 (- time2 time1)) 2 4) " 秒"))(princ))
运行结果:
VLisp函数耗时: 45.269 秒
正则函数耗时: 0.722 秒
可见 VL 函数和正则表达式对字符串的操作效率完全没有可比性。实际上,即使在 vb 或 c 中,用自带的 split 函数也比不上用正则来实现 split 功能的效率,这就是 ActiveX/COM 的优越性。
唯一需要注意的是,在 AutoLisp 和 正则表达式中,不约而同的定义 “\” 为转义字符,所以如果要以单字符“\” 为切割字符,应该用四个 “\\” 来表示,第一次转义为 CAD 字符,第二次转义为正则字符。
例如:
命令: (Split "笨賊a\\shit" "\")
分割字符为单个斜杠是不行的,需要用四个斜杠表示:
命令: (Split "笨賊a\\shit" "\\\\")
- Lisp 语言中 split 的实现方法与效率
- Lua语言string对象的split方法实现
- c语言,模仿js中split方法的函数
- lisp语言的发展
- Lisp语言的理解
- 神奇的LISP语言
- C语言中存储标志(flag)效率最高的方法
- 三种语言递归效率的比较matlab,python,c,lisp....
- C 语言中实现数据与方法的封装
- C 语言中实现数据与方法的封装
- python中split实现字符串分割方法
- C语言实现的lisp解析器介绍
- c语言 split函数的实现
- lisp实现的专家系统
- map的lisp实现
- Lisp 匿名递归函数 v2:在 Common Lisp 中实现 Clojure 的 fn
- Lisp.可扩展的语言
- Lisp.可扩展的语言
- c# 消息框 MessageBox对象的使用
- 慕课网实战项目《WebAPP书城整站开发》笔记六:字体面板中“背景”切换的交互开发
- c语言基础-进制09
- c# 登录界面设计与框架基础搭建雏形--(学生管理系统)
- javabean
- Lisp 语言中 split 的实现方法与效率
- c语言基础系列-原码 反码 补码10
- 代码开源 | COCO-16 图像分割冠军:首个全卷积端到端实例分割模型(HR)
- c语言基础-位运算11
- 推荐Github星级Top10的深度学习项目
- 如何在论文中交代“研究方法”
- TensorFlow,Tensor,Flow(HR)
- 每天学一点Swift----面向对象上(一)
- C++搜索与回溯算法之迷宫问题