Autolisp函数,将文本或多行文本中的数字递增+1。

huangapple go评论64阅读模式
英文:

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 excluding RTEXT.

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)
)

huangapple
  • 本文由 发表于 2023年5月14日 16:22:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/76246520.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定