AutoLISP help

AutoLISP help

Anonymous
Not applicable
1,519 Views
18 Replies
Message 1 of 19

AutoLISP help

Anonymous
Not applicable

Is there an auto lisp program that can wipe the same text (numbers) in different places of the drawing and leave only one no matter where it is. For example, I have the number 2626 that is in the drawing in three different places and I want to leave only one without looking for where the rest are in the drawing. for example two duplicates 2626 should be found among a few hundred other numbers.

Thanks.

0 Likes
Accepted solutions (2)
1,520 Views
18 Replies
Replies (18)
Message 2 of 19

joselggalan
Advocate
Advocate

Try this..

 

;;============================= c:Test0006 ====================================;;
;; Jose L. García G. -  03/10/17                                               ;;
;;=============================================================================;;
(defun c:Test0006 (/ Txt sTxt)
 (cond
  ((and (not (prompt "\nPick Text to find duplicates: "))
	(vl-catch-all-error-p
	 (setq Txt (vl-catch-all-apply 'ssget (list "_:S:E" '((0 . "*TEXT"))))))
   )
  )
  ((not Txt)(prompt "\n¡No select Text.!"))
  (T
   (setq Txt (ssname Txt 0)
	 sTxt (vla-get-Textstring (vlax-ename->vla-object Txt)))
   (cond
    ((and (setq ss (ssget "X" (list '(0 . "*TEXT") (cons 1 sTxt))))
	  (> (sslength ss) 1))
     (setq ss (ssdel Txt ss))
     (vl-cmdf "_.ERASE" ss "")
     (prompt (strcat "\n[" (itoa (sslength ss)) "] texts deleted with string: [" sTxt "]."))
    )
   )
  )
 )
 (princ)
)

Image_10.gif

0 Likes
Message 3 of 19

Anonymous
Not applicable

I have to thank you for the time and effort you set out to solve this problem. The program works great, but I need to select all numbers at the same time, because in a large number of numbers I can't find duplicates as in your case.

Thanks again!

0 Likes
Message 4 of 19

john.uhden
Mentor
Mentor

@joselggalan's contribution is perfect and simple.

The point is that you don't have to find them; his program finds all of the others for you.

But maybe you mean you don't want to have to pick the one you want to keep; instead that the program interprets psychicly what ones to keep and deletes all the duplicates.

As we don't yet have a vla-get-psychic function, is there any criteria to indicate which one(s) to keep (or delete)?  Like layer, color, style, height, angle, etc?

John F. Uhden

0 Likes
Message 5 of 19

DannyNL
Advisor
Advisor

I think I know what you mean; you don't want to select any text but just process all texts in the drawing.

 

I've taken a small part of José-Luis' code and added some of my own.

This code will process the texts with numbers only.

  

(defun c:Test (/ NumberList Txt sTxt)
   (if
      (setq NumberList (GetTextNumbers))
      (progn
         (vla-StartUndoMark (vla-get-ActiveDocument (vlax-get-acad-object)))
         (setvar "CMDECHO" 0)
         (foreach sTxt NumberList
            (if
               (and
                  (setq ss (ssget "X" (list '(0 . "*TEXT") (cons 1 sTxt))))
                  (> (sslength ss) 1)
               )
               (progn           
                  (setq ss (ssdel (ssname ss 0) ss))
                  (vl-cmdf "_.ERASE" ss "")
                  (prompt (strcat "\n[" (itoa (sslength ss)) "] texts deleted with string: [" sTxt "]."))
               )
            )
         )
         (setvar "CMDECHO" 1)
         (vla-EndUndoMark (vla-get-ActiveDocument (vlax-get-acad-object)))
      )        
   )
   (princ)
)

(defun GetTextNumbers (/ GTN_Selection GTN_Number GTN_Return)
   (if
      (setq GTN_Selection (ssget "_X" '((0 . "*TEXT"))))
      (progn
         (foreach GTN_Entity (mapcar 'cadr (ssnamex GTN_Selection))
            (if
               (and
                  (setq GTN_Number (RegEx "^\\d+$" (vla-get-TextString (vlax-ename->vla-object GTN_Entity))))
                  (not (member GTN_Number GTN_Return))
               )
               (setq GTN_Return (append GTN_Return (list GTN_Number)))
            )
         )
      )
   )
   (vl-sort GTN_Return '(lambda (GTN_Text1 GTN_Text2) (< (atoi GTN_Text1) (atoi GTN_Text2))))
)

(defun RegEx (RE_Pattern RE_SearchString / RE_RegExObject RE_Result RE_Return)
   (if
      (and
         (= (type RE_SearchString) 'STR)
         (= (type RE_Pattern)      'STR)
      )
      (progn
         (setq RE_RegExObject (vlax-get-or-create-object "VBScript.RegExp"))
         (vlax-put-property RE_RegExObject 'Pattern RE_Pattern)
         (setq RE_Result (vl-catch-all-apply 'vlax-invoke-method (list RE_RegExObject 'Execute RE_SearchString)))
         (if
            (and
               (not (vl-catch-all-error-p RE_Result))
               (> (vla-get-Count RE_Result) 0)
            )      
            (setq RE_Return (vla-get-Value (vlax-get-property RE_Result 'Item 0)))      
         )
         (vlax-release-object RE_RegExObject)
      )
   )
   RE_Return
)  

 

0 Likes
Message 6 of 19

Anonymous
Not applicable

People, thank you for engaging in solving the problem. Unfortunately, I don't think I have explained very well what the matter is. In the drawing I have a large number of numbers that are in the same layer of the same size and color. Some of these numbers, are repeated (for example number 3366 is located in three different places in the drawing). Is there a solution that when I select all the numbers in the drawing, the program wipes duplicates and leaves only one number 3366? It doesn't matter where it is located.

Thanks again!

0 Likes
Message 7 of 19

DannyNL
Advisor
Advisor

Do you want to select manually like in José-Luis' routine or just select all numbers at once automatically as is the case with my routine?

And what are the conditions? Do the routine need to take the layer in to account, so only leave one number per layer or for the whole drawing?

 

Because if you run my routine it will automatically select all texts, filters only the numbers and leave per number one text while removing all duplicates.

If it is not exactly what you want, can you indicate what you need different in the current routine? Can you post an example to drawing to clarify things?

0 Likes
Message 8 of 19

Anonymous
Not applicable

DannyNL Just what you said. I want to select all the numbers at once. In picture 001 I have an initial situation, for example number 5620 appears four times. and I need the situation as in pic 002. Unfortunately, when I launch your program I get the following message:

 

Command: TEST
; error: no function definition: VLAX-ENAME-VLA-OBJECT

 

Maybe because I have AutoCad 3d 2012 ???

😞

0 Likes
Message 9 of 19

Anonymous
Not applicable

Just like you said Danny, I want to select all the numbers at once and the program clears all the duplicates and leave only one, no matter where it is. In picture 001, I have an initial situation and, for example, the number 5620 appears four times. And I need the situation as in Figure 002.

Unfortunately, when I try your program, I get the following message:

Command: TEST
; error: no function definition:  ( VLAX-ENAME-VLA-OBJECT)

Maybe this is because I have Auto Cad 3D 2012

😞

0 Likes
Message 10 of 19

DannyNL
Advisor
Advisor
Accepted solution

OK, it seems that the Visual LISP core is not loaded. It should be available in 2012 but it might need to be loaded first.

Change this part in the code below

 

(defun c:Test (/ NumberList Txt sTxt)
   (if
      (null vlax-get-acad-object)
      (vl-load-com)
   )
   (if
      (setq NumberList (GetTextNumbers))
      (progn

............

This should make my code work like you want it to.

 

 

Message 11 of 19

joselggalan
Advocate
Advocate
Accepted solution

 

DannyNL:
I think you have to keep in mind that they may contain non-numeric characters.

I have put the search precision in: '(1 . "##*")

 

try this:

 

Image_11.gif

 

(vl-load-com)
;;============================= c:Test0006 ====================================;; ;; Jose L. García G. - 04/10/17 ;; ;;=============================================================================;; (defun c:Test0006 (/ ssAll sTxt LstManaged deleteTxtinDoc) (defun deleteTxtinDoc (sTxt / ss TxtFrt) (cond ((and (setq ss (ssget "X" (list '(0 . "*TEXT") (cons 1 sTxt)))) (> (sslength ss) 1)) (setq TxtFirst (ssname ss 0)) (setq ss (ssdel TxtFirst ss)) (command-s "_.ERASE" ss "") (prompt (strcat "\n[" (itoa (sslength ss)) "] texts deleted with string: [" sTxt "].")) ) ) ) ;;--------------------- MAIN ----------------- (cond ((not (setq ssAll (ssget "X" (list '(0 . "*TEXT") '(1 . "##*"))))) (prompt "\n¡No text was found with numbers in the document.!") ) (T (vla-StartUndoMark (vla-get-ActiveDocument (vlax-get-acad-object))) (setq lstTxt (vl-remove-if 'listp (mapcar 'cadr (ssnamex ssAll)))) (mapcar (function (lambda ( eTxt / oTxt sTxt) (cond ((not (vlax-erased-p etxt)) (setq oTxt (vlax-ename->vla-object eTxt) sTxt (vla-get-Textstring oTxt)) (if (not (vl-position sTxt LstManaged)) (progn (setq LstManaged (cons sTxt LstManaged)) (deleteTxtinDoc sTxt) ) );c.if ) ) ) ) lstTxt );c.mapcar (vla-EndUndoMark (vla-get-ActiveDocument (vlax-get-acad-object))) ) );c.cond (princ) )

 

 

Message 12 of 19

Anonymous
Not applicable

U guys are fantastic, thank you very much for your efforts. You saved me a huge problem and saved hours of work.
Thanks once again, best regards !!!!

0 Likes
Message 13 of 19

Anonymous
Not applicable

You guys are fantastic, thank you very much for your efforts. You saved me a huge problem and saved hours of work.
Thanks once again, best regards !!!!

 
0 Likes
Message 14 of 19

DannyNL
Advisor
Advisor

You're welcome and glad we could help Smiley Happy

 

@joselggalan

That would be a possibility, but the description the OP gives are only numbers and also the examples contain only numbers.

And although the pattern filtering of SSGET does do a nice job, it's pretty limited in it's use.

 

For example you can only control a specific number of digits in the filtering and not a flexible number of digits. Of course you can chain some conditions with <-4 .... AND ... AND -4>, but then you would have to include all possibilities.

 

That's the reason why I'm using regular expressions in my filtering as it is more powerful and advanced then the built-in filtering. In this case my filtering checks for texts that only consists of numbers with at least one number, so it will get a text "2" but also "1234567890" but not if there is somewhere any other character included like "x1234", "12x34" or "1234x".

 

But if needed the pattern can be modified to check for other combinations as well.

0 Likes
Message 15 of 19

joselggalan
Advocate
Advocate

In the jpg file attached (2626.JPG) in post # 1, note that they are not just numbers:
2624/1, 2624/2, 2841/2, ...

Not so in the later examples ....

 

In any case this great use "VBScript.RegExp" for filtering.

 

regards.

 

Message 16 of 19

DannyNL
Advisor
Advisor

Oops....you are right. I missed that one and only saw the other image files from post #8 Smiley Surprised

 

In that case you would need an additional condition in RegEx to check first for the / in the text with (RegEx "\\d+/\\d+" textvar) before checking for numbers only.

0 Likes
Message 17 of 19

john.uhden
Mentor
Mentor

Just a second, Danny...

 

(ssget "X" '((0 . "TEXT")(1 . "#,##,###,####")))

John F. Uhden

0 Likes
Message 18 of 19

DannyNL
Advisor
Advisor

Yes John? What about it?

And what about 12345, 123456 or 1234567890?

 

I know you can add multiple filters to the SSGET but you have to specify each possible pattern separately. Although not directly usable in SSGET, using regular expressions to filter texts is way more advanced then the built-in filters in SSGET and WCMATCH.

What if you want to select all texts containing only numbers, but it doesn't matter if it is one number, 22 numbers or even hundred numbers?

 

The RegExp object can be used as a replacement for WCMATCH, but has more features as it can easily be configured to be case-sensitive, to find and return multiple matching patterns from one string (i.e. return 123, 456, 789 from 123abc456def789) and replace a string (i.e. return XXXabcXXXdefXXX from 123abc456def789).

 

That said, in this case if the numbers are always and only in the format #### or ####/# it would be easier to use the filtering in the SSGET.

0 Likes
Message 19 of 19

john.uhden
Mentor
Mentor

Thank you, Danny, for that information.  I don't have any personal experience with regular expressions, but I think that Joe Burke and Steve Doman ended up using it in their STRIPMTEXT routine.  There was one example of it used here this past year, but I think it failed.  I should give it more of my attention.

John F. Uhden

0 Likes