当前位置:首页>python>像Python一样玩转字符串!AutoLISP也能用负数索引截取子串了

像Python一样玩转字符串!AutoLISP也能用负数索引截取子串了

  • 2026-10-11 07:49:08
像Python一样玩转字符串!AutoLISP也能用负数索引截取子串了
告别生硬的 substr,让你的代码更优雅

在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保持一致):

  • 索引从 0 开始(第一个字符是0)

  • 负数表示倒数:-1 表示最后一个字符,-2 表示倒数第二个……

  • 起始索引 a 默认值为 0(即从头开始)

  • 结束索引 b 默认值为 strlen(str)-1(即最后一个字符)

转换公式:

  • 若 a >= 0 → 物理位置 a

  • 若 a < 0 → 物理位置 (strlen str) + a(因为 a 是负值,实际得到尾部偏移)

2️⃣ 正向截取 vs 反向截取

Python 中 s[7:3] 不会报错,而是返回空字符串。但为了让 substrx 更实用,我们做了增强:

  • 当 结束索引 ≥ 起始索引 时,按正常顺序截取。

  • 当 结束索引 < 起始索引 时,自动反向截取并反转结果。

这就实现了类似 s[7:3:-1] 的效果,一步拿到反转的子串。

3️⃣ 字符串反转的简洁实现

(vl-list->string (reverse (vl-string->list 某字符串)))
  • vl-string->list :将字符串拆分成 ASCII 码列表

  • reverse :反转列表顺序

  • vl-list->string :将 ASCII 码列表拼回字符串

三者的组合是 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 的优势

场景原生 substrsubstrx
取末尾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二次开发的朋友~ 💡

最新文章

随机文章