英文:
Autolisp function that Increment numbers intext or mtext +1
问题
I'm not overly familiar with AutoLISP, but here's the translated code:
(defun c:IncrementTextNumbers (/ ss obj)
(setq ss (ssget '((0 . "TEXT")(62 . 1))))
(if ss
(progn
(setq obj (ssname ss 0))
(while obj
(if (and (= (cdr (assoc 0 (entget obj))) "TEXT")
(numberp (atoi (cdr (assoc 1 (entget obj))))))
(progn
(setq num (atoi (cdr (assoc 1 (entget obj)))))
(setq new-num (+ num 1))
(command "_CHANGE" obj "" new-num)
)
)
(setq obj (ssname ss (1+ (ssname ss (sslength ss) obj))))
)
(princ "\nHighlighted text numbers incremented successfully.")
)
(princ "\nNo highlighted text objects found.")
)
(princ)
This is the translated AutoLISP code without the need for further explanation.
英文:
I'm not overly familar with AutoLISP having a problem writing a script that increments numbers in Text or MText by 1, preferably all selected text.
(defun c:IncrementTextNumbers (/ ss obj)
(setq ss (ssget '((0 . "TEXT")(62 . 1))))
(if ss
(progn
(setq obj (ssname ss 0))
(while obj
(if (and (= (cdr (assoc 0 (entget obj))) "TEXT")
(numberp (atoi (cdr (assoc 1 (entget obj))))))
(progn
(setq num (atoi (cdr (assoc 1 (entget obj)))))
(setq new-num (+ num 1))
(command "_.CHANGE" obj "" new-num)
)
)
(setq obj (ssname ss (1+ (ssname ss (sslength ss) obj))))
)
(princ "\nHighlighted text numbers incremented successfully.")
)
(princ "\nNo highlighted text objects found.")
)
(princ)
答案1
得分: 2
以下是翻译好的内容:
选集处理
您的代码主要问题是迭代选择集的方法,具体来说,是这行代码:
(setq obj (ssname ss (1+ (ssname ss (sslength ss) obj))))
ssname
函数接受一个选择集和一个索引作为参数;在最内部的表达式中,您提供了一个选择集 (ss
)、一个索引 ((sslength ss)
) 和一个实体名称 (obj
)。另外,ssname
返回一个实体名称,您不能用 1+
函数对其进行递增。
我建议您学习我的关于选择集处理的教程,以了解在选择集上迭代的不同方法。
对于这个特定的示例,我可能会使用我的教程中描述的反向重复技术,因为这可以产生简洁且高效的代码,例如:
(defun c:IncrementTextNumbers ( / idx sel )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
;; ... 做一些操作 ...
)
)
)
(princ)
)
在这里,您还会注意到我已经修改了 ssget
表达式如下:
"_:L"
模式字符串排除了锁定图层上的对象 - 下划线确保使用非本地化版本的模式字符串。- 在选择过滤器中使用
TEXT,MTEXT
允许用户选择单行文本和多行文本,同时排除了RTEXT
。
字符串转换为数字
首先,我应该注意,您的程序中的这行代码是不必要的:
(= (cdr (assoc 0 (entget obj))) "TEXT")
因为您已经在 ssget
选择过滤器中过滤了 TEXT
实体。
其次,您应该知道,atoi
无论输入文本如何,都会始终返回一个数字值,如下所示:
_$ (atoi "abc")
0
因此,表达式 (numberp (atoi ...))
将始终返回 T
,对于所有文本内容都是如此。
由于在这种情况下,您也无法测试非零内容(因为内容可能合法地为零),我建议要么使用 distof
函数进行字符串转换为数字(因为此函数将在非数值输入时返回 nil
),要么如果要限制输入仅为整数,则可以使用 wcmatch
函数来测试字符串是否仅包含数字(或更好的做法是将此测试纳入 ssget
选择过滤器中)。以下是每种方法的示例:
使用 distof
(defun c:IncrementTextNumbers ( / enx idx sel str )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
str (cdr (assoc 1 enx))
)
(if (distof str 2)
;; ... 做一些操作 ...
)
)
)
(princ)
)
使用 wcmatch
(测试正整数)
(defun c:IncrementTextNumbers ( / enx idx sel str )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
str (cdr (assoc 1 enx))
)
(if (wcmatch str "~*[~0-9]*")
;; ... 做一些操作 ...
)
)
)
(princ)
)
使用 ssget
过滤器(测试正整数)
(defun c:IncrementTextNumbers ( / enx idx sel str )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT") (1 . "~*[~0-9]*"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
str (cdr (assoc 1 enx))
)
;; ... 做一些操作 ...
)
)
(princ)
)
使用 entmod
替代命令
最后,您可以使用 entmod
直接修改绘图数据库的内容,而不是使用 AutoCAD 命令执行此操作(后者更慢且不太可靠,因为您依赖于提示的顺序在 AutoCAD 版本之间保持不变)。
考虑以下代码:
(defun c:IncrementTextNumbers ( / enx idx itm sel )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT") (1 . "~*[~0-9]*"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
itm (assoc 1 enx)
)
(entmod (subst (cons 1 (itoa (1+ (atoi (cdr itm))))) itm enx))
)
)
(princ)
)
英文:
Selection Set Processing
The main issue with your code is the method used to iterate over the selection set - specifically, this line:
(setq obj (ssname ss (1+ (ssname ss (sslength ss) obj))))
The ssname
function accepts as arguments a selection set and an index; here, in the innermost expression, you are supplying a selection set (ss
), an index ((sslength ss)
), and an entity name (obj
). Also ssname
returns an entity name, which you cannot increment with the 1+
function.
I would suggest studying my tutorial on Selection Set Processing to understand various ways of iterating over a selection set.
For this particular example, I might use the 'reverse repeat' technique described in my tutorial, as this yields concise & efficient code e.g.:
(defun c:IncrementTextNumbers ( / idx sel )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
;; ... do stuff ...
)
)
)
(princ)
)
Here, you'll also note that I've revised the ssget
expression in the following way:
- The
"_:L"
mode string excludes objects on locked layers - the underscore ensures that the non-localised version of the mode string is used. - The use of
TEXT,MTEXT
in the selection filter allows the user to select both single-line text and MText, whilst excludingRTEXT
.
String to Number Conversion
Firstly, I should note that this line in your program is not necessary:
(= (cdr (assoc 0 (entget obj))) "TEXT")
As you're already filtering for TEXT
entities in the ssget
selection filter.
Secondly, you should be aware that atoi
will unhelpfully always return a numerical value, regardless of the input text, observe:
_$ (atoi "abc")
0
Hence, the expression (numberp (atoi ...))
will always return T
, for all text content.
Since you also can't test for non-zero content in this case (as the content could be legitimately zero), I would suggest either using the distof
function for the string to number conversion (as this function will return nil
for non-numerical input), or if you want to restrict the input to only integers, you can use the wcmatch
function to test whether the string contains only digits (or better yet, incorporate this test into the ssget
selection filter).
Here's an example of each method:
Using distof
(defun c:IncrementTextNumbers ( / enx idx sel str )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
str (cdr (assoc 1 enx))
)
(if (distof str 2)
;; ... do stuff ...
)
)
)
(princ)
)
Using wcmatch
(testing for positive integers)
(defun c:IncrementTextNumbers ( / enx idx sel str )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
str (cdr (assoc 1 enx))
)
(if (wcmatch str "~*[~0-9]*")
;; ... do stuff ...
)
)
)
(princ)
)
Using the ssget
filter (testing for positive integers
(defun c:IncrementTextNumbers ( / enx idx sel str )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT") (1 . "~*[~0-9]*"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
str (cdr (assoc 1 enx))
)
;; ... do stuff ...
)
)
(princ)
)
Using entmod
in place of Commands
Finally, you could make use of entmod
to modify the content of the drawing database directly, rather than performing this operation using an AutoCAD command (which is slower and less reliable, as you are reliant upon the order of the prompts remaining unchanged between AutoCAD releases).
Consider the following code:
(defun c:IncrementTextNumbers ( / enx idx itm sel )
(if (setq sel (ssget "_:L" '((0 . "TEXT,MTEXT") (1 . "~*[~0-9]*"))))
(repeat (setq idx (sslength sel))
(setq idx (1- idx)
enx (entget (ssname sel idx))
itm (assoc 1 enx)
)
(entmod (subst (cons 1 (itoa (1+ (atoi (cdr itm))))) itm enx))
)
)
(princ)
)
答案2
得分: 0
You should use (entmod)
而不是 change
。还简化了您的示例。尝试以下代码。
(defun c:IncrementTextNumbers (/ ss obj)
(setq ss (ssget '((0 . "TEXT"))))
(if ss
(progn
(setq index 0)
(setq obj (ssname ss index))
(while obj
(setq content (cdr (assoc 1 (entget obj))))
(setq num (atoi content))
(if (numberp num)
(progn
(setq new-num (1+ num))
(setq ed (entget obj))
(setq ed (subst (cons 1 (itoa new-num)) (assoc 1 ed) ed))
(entmod ed)
)
)
(setq index (1+ index))
(setq obj (ssname ss index))
)
(princ "\nHighlighted text numbers incremented successfully.")
)
(princ "\nNo highlighted text objects found.")
)
(princ)
)
请注意,我只翻译了代码部分,其他内容保持不变。
英文:
You should use (entmod )
instead of change. Also simplified Your sample. Try this code.
(defun c:IncrementTextNumbers (/ ss obj)
(setq ss (ssget '((0 . "*TEXT"))))
(if ss
(progn
(setq index 0)
(setq obj (ssname ss index))
(while obj
(setq content (cdr (assoc 1 (entget obj))))
(setq num (atoi content))
(if (numberp num)
(progn
(setq new-num (1+ num ))
(setq ed (entget obj))
(setq ed (subst (cons 1 (itoa new-num)) (assoc 1 ed) ed))
(entmod ed)
)
)
(setq index(1+ index ))
(setq obj (ssname ss index))
)
(princ "\nHighlighted text numbers incremented successfully.")
)
(princ "\nNo highlighted text objects found.")
)
(princ)
)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论