在AutoLISP的日常开发中,字符串处理几乎避不开。但内置的 substr 函数有一个“硬伤”——索引只能从1开始正向计数,不支持负数从尾部取字符,更别提像Python那样用 [start:end] 灵活切片了。
每次想取字符串最后几个字符,都得先算 strlen,再套 substr,代码又长又容易算错……
现在,我们有了 substrx —— 一个支持负数索引、正反向截取的字符串万能函数。
一、效果预览
先看几个例子,感受一下:
(setq s "Hello, AutoCAD!")(substrx s -6 -1) ;; → "CAD" (倒数第6到倒数第2)(substrx s -6) ;; → "CAD!" (从倒数第6到末尾)(substrx s 7 -8) ;; → "o, Au" (正向7到倒数8,反向截取)(substrx s 7 10) ;; → "o, A" (常规正向切片)
是不是很像Python的 s[-6:-1]、s[-6:] ?对的,substrx 的目标就是把Python字符串切片的便利带给AutoLISP。
二、完整代码
;; 增强版字符串截取;; 参数:;; str - 源字符串;; a - 起始索引(支持负数,从0开始计数,负数为从末尾倒数);; b - 结束索引(可选,负数同理;不提供则截取到末尾);; 返回:截取出的子串(若a>b则返回反转后的子串)(defun substrx (str a b / n1 n2) (setq n1 (if a (if (>= a 0) a (+ (strlen str) a) ) 0 ) n2 (if b (if (>= b 0) b (+ (strlen str) b) ) (1- (strlen str)) ) ) (if (>= n2 n1) (substr str (1+ n1) (- n2 n1 -1)) ;; 反向截取:先取反向片段,再反转字符串 (vl-list->string (reverse (vl-string->list (substr str (1+ n2) (- n1 n2 -1)) ) ) ) ))
亮点:利用 vl-string->list + reverse + vl-list->string 一行完成字符串反转,无需手写循环。三、核心原理解析
1️⃣ 负数索引的转换
AutoLISP的 substr 要求起始位置 ≥ 1,所以我们需要把用户传入的“逻辑索引”映射成物理位置。
规则约定(与Python保持一致):
转换公式:
2️⃣ 正向截取 vs 反向截取
Python 中 s[7:3] 不会报错,而是返回空字符串。但为了让 substrx 更实用,我们做了增强:
这就实现了类似 s[7:3:-1] 的效果,一步拿到反转的子串。
3️⃣ 字符串反转的简洁实现
(vl-list->string (reverse (vl-string->list 某字符串)))
三者的组合是 VL 扩展中最常用的字符串反转技巧,性能好且代码优雅。
四、常用示例汇总
| 需求 | 写法 | 结果 |
|---|
| 取前3个字符 | (substrx "ABCDE" 0 3) | "ABC" |
| 取第2~第4个字符 | (substrx "ABCDE" 1 4) | "BCD" |
| 取最后2个字符 | (substrx "ABCDE" -2) | "DE" |
| 取倒数第4到倒数第2 | (substrx "ABCDE" -4 -2) | "BC" |
| 从索引3往前取到索引0(反向) | (substrx "ABCDE" 3 0) | "DCBA" |
| 去掉首尾各一个字符 | (substrx "ABCDE" 1 -2) | "BCD" |
五、相比原生 substr 的优势
| 场景 | 原生 substr | substrx |
|---|
| 取末尾3个字符 | (substr str (- (strlen str) 2)) | (substrx str -3) |
| 取中间一段 | 需手动计算长度 | 直接写起止索引 |
| 反向截取 | 要配合循环或递归 | 自动反转 |
| 代码可读性 | 较差,易错 | 一目了然 |
六、进阶技巧:组合使用
你可以把 substrx 和其他字符串函数串联,写出非常简洁的解析逻辑:
;; 提取文件扩展名(defun get-extension (filename) (substrx filename (+ (vl-string-position 46 filename) 1) -1));; 反转单词顺序(假设单词间用空格分隔)(defun reverse-words (str) (substrx str -1 0));; 判断字符串是否为回文(defun palindrome-p (str) (setq str (vl-string-trim " " str)) (equal str (substrx str -1 0)))
七、写在最后
substrx 虽然只有短短十几行,但它彻底释放了AutoLISP处理字符串的灵活性。无论是CAD图元属性解析、用户输入处理,还是文本文件读写,都能让你的代码更短、更清晰。
我把它收录到了自己的工具库中,几乎每个项目都会用到。如果你也有同样的痛点,不妨复制粘贴到你的 lsp 文件里,一劳永逸。
开源与分享
本文代码完全开放,你可以任意修改、使用。如果有更好的实现方式(比如支持步长),欢迎在评论区交流。
喜欢这种让AutoLISP更现代化的技巧吗?点个「在看」,分享给更多CAD二次开发的朋友~ 💡