Jump to content

Change Attribute Tags for Blocks using Lisp


hosannabizarre

Recommended Posts

When I run the code below it lets me load and enter the command, but it doesn't change anything. There are no errors. I only edited the spot of the "old tag" and the "new tag" to my required values.

 

Is there something else I am missing here?

 

I need to change the values of multiple attribute tags to the same value on a large number of different blocks permanantly.

 

Thanks,

 

 

 

I read 5 minutes ago that attribute tags are unchangable without exploding.

 

Then I found a lisp which completely disproves that statement, and I'm damn pleased I found it.

 

If you ever want to change the tag names for attributed blocks use the following, creating a list of old & new tag names.

 

(defun c:attr_rename_list (  / x_en enn edd ss slen ix atnam 
          namelist hit blk_ent
          matchname newed x) 
 ; Process all block instances on active drawing. Check each 
 ; attribute for match on first element in list below. On any
 ; match, rename the attribute to the new name given in the
 ; second element. 

 ; ***********   ATTRIBUTE OLD versus NEW names list   ******************
 (setq namelist (list
     ; list old name and new name. Old name can contain wild cards.
     (list "OLD_TAG_NAME#1" "NEW_TAG_NAME#1")  ; list old name and new name. 
     (list "OLD_TAG_NAME#2" "NEW_TAG_NAME#2")
     (list "OLD_TAG_NAME#3" "NEW_TAG_NAME#3")
     (list "OLD_TAG_NAME#4" "NEW_TAG_NAME#4")
     (list "OLD_TAG_NAME#5" "NEW_TAG_NAME#5")
 ) )  
 ; **********************************************************************

 ; Extract selection set of all block inserts on active drawing  
 (setq ss (ssget "_X" '((0 . "INSERT"))))
 (if (/= ss nil)
   (progn
     (setq slen (sslength ss))
     (setq ix 0)
     (while (< ix slen)
       (setq blk_ent (ssname ss ix)) ; get next block insert to process        
       (setq ix (1+ ix)) ; increment for next time
       (setq enn (entnext blk_ent)) 
       (setq edd (entget enn))  
       (while (AND enn (/= (cdr (assoc 0 edd)) "SEQEND") 
                           (/= (cdr (assoc 0 edd)) "INSERT") )
         (if (= (cdr (assoc 0 edd)) "ATTRIB")
           (progn
             (setq atnam (cdr (assoc 2 edd)))
             (setq hit nil)
             (foreach x namelist
               (if (not hit)
                 (progn ; no match yet, keep processing
                   (setq matchname (car x))                
                   (if (wcmatch atnam matchname) 
                     (progn ; found exact match or wild-card match
                       ; Change name now. Substitute in new name.
                       (setq newed (subst (cons 2 (cadr x)) (assoc 2 edd) edd)) 
                       (entmod newed) ; update the title block instance
                       (entupd blk_ent) 
                       (princ "\n")
                       (princ atnam)
                       (princ " --> ")
                       (princ (cadr x))
                       (setq hit 1) ; flag that found
               ) ) ) )
             )
           )
         )     
         ; go to next sub ent in block instance and loop back up
         (if (setq enn (entnext enn)) (setq edd (entget enn))) 
     ) ) 
     (setq ss nil) ; release the selection set
   )
 )
 (princ) ; prettier
)

I love finding the answer. It makes me feel alive.:D

Link to comment
Share on other sites

  • Replies 33
  • Created
  • Last Reply

Top Posters In This Topic

  • pBe

    7

  • MACNEIL

    7

  • wrightjd

    6

  • Roy_043

    5

Top Posters In This Topic

Posted Images

I would suggest just listing all the attributes that require changing on the left, and then it's okay to have a repeated value, if they all need to be changed to the same thing.

 

It should work. Here is the original code that I found and then used to input OLD/NEW attribute titles:

 

(defun c:attr_rename_list (  / x_en enn edd ss slen ix atnam 
          namelist hit blk_ent
          matchname newed x) 

 ; Process all block instances on active drawing. Check each 
 ; attribute for match on first element in list below. On any
 ; match, rename the attribute to the new name given in the
 ; second element. 

 ; ***********   ATTRIBUTE OLD versus NEW names list   ******************
 (setq namelist (list
     ; list old name and new name. Old name can contain wild cards.
     (list "format" "S")  ; list old name and new name. 
     (list "fail_type" "I")
 ) )  
 ; **********************************************************************
 
 ; Extract selection set of all block inserts on active drawing  
 (setq ss (ssget "_X" '((0 . "INSERT"))))
 (if (/= ss nil)
   (progn
     (setq slen (sslength ss))
     (setq ix 0)
     (while (< ix slen)
       (setq blk_ent (ssname ss ix)) ; get next block insert to process        
       (setq ix (1+ ix)) ; increment for next time
       (setq enn (entnext blk_ent)) 
       (setq edd (entget enn))  
       (while (AND enn (/= (cdr (assoc 0 edd)) "SEQEND") 
                           (/= (cdr (assoc 0 edd)) "INSERT") )
         (if (= (cdr (assoc 0 edd)) "ATTRIB")
           (progn
             (setq atnam (cdr (assoc 2 edd)))
             (setq hit nil)
             (foreach x namelist
               (if (not hit)
                 (progn ; no match yet, keep processing
                   (setq matchname (car x))                
                   (if (wcmatch atnam matchname) 
                     (progn ; found exact match or wild-card match
                       ; Change name now. Substitute in new name.
                       (setq newed (subst (cons 2 (cadr x)) (assoc 2 edd) edd)) 
                       (entmod newed) ; update the title block instance
                       (entupd blk_ent) 
                       (princ "\n")
                       (princ atnam)
                       (princ " --> ")
                       (princ (cadr x))
                       (setq hit 1) ; flag that found
               ) ) ) )
             )
           )
         )     
         ; go to next sub ent in block instance and loop back up
         (if (setq enn (entnext enn)) (setq edd (entget enn))) 
     ) ) 
     (setq ss nil) ; release the selection set
   )
 )
 (princ) ; prettier

Edited by SLW210
Added Code Tags
Link to comment
Share on other sites

Hmmmm, well not sure why it's not working. I tried the both codes again with only one block in a new drawing. I even tried changing the tag to match the one in the codes and still no dice. The programs load OK and they run with no errors. I tried to attsync and then looked in the block and nothing changes.

 

Can anyone take a look at the code for me? I am not very knowledgeable in lisp routines. Thanks,

 

 

I would suggest just listing all the attributes that require changing on the left, and then it's okay to have a repeated value, if they all need to be changed to the same thing.

 

It should work. Here is the original code that I found and then used to input OLD/NEW attribute titles:

 

(defun c:attr_rename_list (  / x_en enn edd ss slen ix atnam 
          namelist hit blk_ent
          matchname newed x) 

 ; Process all block instances on active drawing. Check each 
 ; attribute for match on first element in list below. On any
 ; match, rename the attribute to the new name given in the
 ; second element. 

 ; ***********   ATTRIBUTE OLD versus NEW names list   ******************
 (setq namelist (list
     ; list old name and new name. Old name can contain wild cards.
     (list "format" "S")  ; list old name and new name. 
     (list "fail_type" "I")
 ) )  
 ; **********************************************************************
 
 ; Extract selection set of all block inserts on active drawing  
 (setq ss (ssget "_X" '((0 . "INSERT"))))
 (if (/= ss nil)
   (progn
     (setq slen (sslength ss))
     (setq ix 0)
     (while (< ix slen)
       (setq blk_ent (ssname ss ix)) ; get next block insert to process        
       (setq ix (1+ ix)) ; increment for next time
       (setq enn (entnext blk_ent)) 
       (setq edd (entget enn))  
       (while (AND enn (/= (cdr (assoc 0 edd)) "SEQEND") 
                           (/= (cdr (assoc 0 edd)) "INSERT") )
         (if (= (cdr (assoc 0 edd)) "ATTRIB")
           (progn
             (setq atnam (cdr (assoc 2 edd)))
             (setq hit nil)
             (foreach x namelist
               (if (not hit)
                 (progn ; no match yet, keep processing
                   (setq matchname (car x))                
                   (if (wcmatch atnam matchname) 
                     (progn ; found exact match or wild-card match
                       ; Change name now. Substitute in new name.
                       (setq newed (subst (cons 2 (cadr x)) (assoc 2 edd) edd)) 
                       (entmod newed) ; update the title block instance
                       (entupd blk_ent) 
                       (princ "\n")
                       (princ atnam)
                       (princ " --> ")
                       (princ (cadr x))
                       (setq hit 1) ; flag that found
               ) ) ) )
             )
           )
         )     
         ; go to next sub ent in block instance and loop back up
         (if (setq enn (entnext enn)) (setq edd (entget enn))) 
     ) ) 
     (setq ss nil) ; release the selection set
   )
 )
 (princ) ; prettier

Link to comment
Share on other sites

I tried yesterday with capitals and just to be sure I tried again today.

 

I made a brand new drawing with a new block and def and still get the same result.

 

Here's the CAD file. Thanks.

 

TEST2.dwg

 

@MACNEIL:

Change the tagstrings in the namelist to upper case.

If that does not help post a dwg.

Link to comment
Share on other sites

Your problem is caused by the '#' character which is a special wcmatch character that matches any single digit:

(wcmatch "OLD_TAG_NAME#1" "OLD_TAG_NAME#1")  => nil
(wcmatch "OLD_TAG_NAME01" "OLD_TAG_NAME#1")  => T
(wcmatch "OLD_TAG_NAME11" "OLD_TAG_NAME#1")  => T
...
(wcmatch "OLD_TAG_NAME91" "OLD_TAG_NAME#1")  => T 
(wcmatch "OLD_TAG_NAME#1" "OLD_TAG_NAME`#1") => T (escaped special character)

This easiest fix is to replace:

(wcmatch atnam matchname)

with:

(= atnam matchname)

Link to comment
Share on other sites

Hey,

 

Sorry haven't had a chance to try this out until just now.

I cannot get this to work still. I am more than likely misunderstanding something. Can you please take a look?

 

(defun c:attr_rename_list (  / x_en enn edd ss slen ix atnam 
          namelist hit blk_ent
          matchname newed x) 
 ; Process all block instances on active drawing. Check each 
 ; attribute for match on first element in list below. On any
 ; match, rename the attribute to the new name given in the
 ; second element. 

 ; ***********   ATTRIBUTE OLD versus NEW names list   ******************
 (setq namelist (list
     ; list old name and new name. Old name can contain wild cards.
(wcmatch "ITEM\U+0020#" "OLD_TAG_NAME#1")  => nil
(wcmatch "OLD_TAG_NAME01" "OLD_TAG_NAME#1")  => T
(wcmatch "OLD_TAG_NAME11" "OLD_TAG_NAME#1")  => T
...
(wcmatch "OLD_TAG_NAME91" "OLD_TAG_NAME#1")  => T 
(wcmatch "OLD_TAG_NAME#1" "OLD_TAG_NAME`#1") => T (escaped special character)
 ) )  
 ; **********************************************************************

 ; Extract selection set of all block inserts on active drawing  
 (setq ss (ssget "_X" '((0 . "INSERT"))))
 (if (/= ss nil)
   (progn
     (setq slen (sslength ss))
     (setq ix 0)
     (while (< ix slen)
       (setq blk_ent (ssname ss ix)) ; get next block insert to process        
       (setq ix (1+ ix)) ; increment for next time
       (setq enn (entnext blk_ent)) 
       (setq edd (entget enn))  
       (while (AND enn (/= (cdr (assoc 0 edd)) "SEQEND") 
                           (/= (cdr (assoc 0 edd)) "INSERT") )
         (if (= (cdr (assoc 0 edd)) "ATTRIB")
           (progn
             (setq atnam (cdr (assoc 2 edd)))
             (setq hit nil)
             (foreach x namelist
               (if (not hit)
                 (progn ; no match yet, keep processing
                   (setq matchname (car x))                
                   (if (atnam matchname) 
                     (progn ; found exact match or wild-card match
                       ; Change name now. Substitute in new name.
                       (setq newed (subst (cons 2 (cadr x)) (assoc 2 edd) edd)) 
                       (entmod newed) ; update the title block instance
                       (entupd blk_ent) 
                       (princ "\n")
                       (princ atnam)
                       (princ " --> ")
                       (princ (cadr x))
                       (setq hit 1) ; flag that found
               ) ) ) )
             )
           )
         )     
         ; go to next sub ent in block instance and loop back up
         (if (setq enn (entnext enn)) (setq edd (entget enn))) 
     ) ) 
     (setq ss nil) ; release the selection set
   )
 )
 (princ) ; prettier
)

 

Also I use the unicode for space in some of my tags. Will this mess this up?

 

Thanks!

 

Your problem is caused by the '#' character which is a special wcmatch character that matches any single digit:

(wcmatch "OLD_TAG_NAME#1" "OLD_TAG_NAME#1")  => nil
(wcmatch "OLD_TAG_NAME01" "OLD_TAG_NAME#1")  => T
(wcmatch "OLD_TAG_NAME11" "OLD_TAG_NAME#1")  => T
...
(wcmatch "OLD_TAG_NAME91" "OLD_TAG_NAME#1")  => T 
(wcmatch "OLD_TAG_NAME#1" "OLD_TAG_NAME`#1") => T (escaped special character)

This easiest fix is to replace:

(wcmatch atnam matchname)

with:

(= atnam matchname)

Link to comment
Share on other sites

(defun c:attr_rename_list ( / elst enm i new nmeLst old ss)

 (setq nmeLst ; All tags must be upper case.
   (list
     ;     OLD                                     NEW
     (list "TAGWITH\U+00A0UNICODENONBREAKINGSPACE" "S") ; \U+00A0 = Unicode non-breaking space.
     (list "TAG2"                                  "I")
   )
 )

 (if (setq ss (ssget "_X" '((0 . "INSERT") (66 . 1))))
   (repeat (setq i (sslength ss))
     (setq enm (ssname ss (setq i (1- i))))
     (while
       (and
         (setq enm (entnext enm))
         (setq elst (entget enm))
         (= "ATTRIB" (cdr (assoc 0 elst)))
       )
       (if (setq new (cadr (assoc (setq old (cdr (assoc 2 elst))) nmeLst)))
         (progn
           (entmod (subst (cons 2 new) (cons 2 old) elst))
           (princ (strcat "\n" old " --> " new " "))
         )
       )
     )
   )
 )
 (princ)
)

Edited by Roy_043
Cleaned up the code.
Link to comment
Share on other sites

@Roy_043

 

Everything is working great now, except a major problem.

 

This is not a permanent solution, because soon as I attsync the attribute value reverts back to the original. Is there a way to do this to the tag name inside of the block?

 

Mod please disregard my last post.

 

Thanks you.

 

(defun c:attr_rename_list ( / elst enm i new nmeLst old ss)

 (setq nmeLst ; All tags must be upper case.
   (list
     ;     OLD                                     NEW
     (list "TAGWITH\U+00A0UNICODENONBREAKINGSPACE" "S") ; \U+00A0 = Unicode non-breaking space.
     (list "TAG2"                                  "I")
   )
 )

 (if (setq ss (ssget "_X" '((0 . "INSERT") (66 . 1))))
   (repeat (setq i (sslength ss))
     (setq enm (ssname ss (setq i (1- i))))
     (while
       (and
         (setq enm (entnext enm))
         (setq elst (entget enm))
         (= "ATTRIB" (cdr (assoc 0 elst)))
       )
       (if (setq new (cadr (assoc (setq old (cdr (assoc 2 elst))) nmeLst)))
         (progn
           (entmod (subst (cons 2 new) (cons 2 old) elst))
           (princ (strcat "\n" old " --> " new " "))
         )
       )
     )
   )
 )
 (princ)
)

Link to comment
Share on other sites

(defun c:AttRenList ( / doc new tagLst)

 (setq tagLst ; All tags must be upper case.
   (list
     ;     OLD                                     NEW
     (list "TAGWITH\U+00A0UNICODENONBREAKINGSPACE" "S") ; \U+00A0 = Unicode non-breaking space.
     (list "TAG2"                                  "I")
   )
 )

 (setq doc (vla-get-activedocument (vlax-get-acad-object)))
 (vla-endundomark doc)
 (vla-startundomark doc)
 (vlax-for blk (vla-get-blocks doc)
   (if (= :vlax-false (vla-get-isxref blk))
     (vlax-for obj blk
       (cond
         ((= "AcDbBlockReference" (vla-get-objectname obj))
           (if (= :vlax-true (vla-get-hasattributes obj))
             (foreach att (vlax-invoke obj 'getattributes)
               (if (setq new (cadr (assoc (vla-get-tagstring att) tagLst)))
                 (vla-put-tagstring att new)
               )
             )
           )

         )
         ((= "AcDbAttributeDefinition" (vla-get-objectname obj))
           (if (setq new (cadr (assoc (vla-get-tagstring obj) tagLst)))
             (vla-put-tagstring obj new)
           )
         )
       )
     )
   )
 )
 (vla-endundomark doc)
 (princ)
)

Link to comment
Share on other sites

  • 6 years later...
On 8/9/2010 at 10:20 AM, hosannabizarre said:

 

(defun c:attr_rename_list (  / x_en enn edd ss slen ix atnam 
          namelist hit blk_ent
          matchname newed x) 
 ; Process all block instances on active drawing. Check each 
 ; attribute for match on first element in list below. On any
 ; match, rename the attribute to the new name given in the
 ; second element. 

 ; ***********   ATTRIBUTE OLD versus NEW names list   ******************
 (setq namelist (list
     ; list old name and new name. Old name can contain wild cards.
     (list "OLD_TAG_NAME#1" "NEW_TAG_NAME#1")  ; list old name and new name. 
     (list "OLD_TAG_NAME#2" "NEW_TAG_NAME#2")
     (list "OLD_TAG_NAME#3" "NEW_TAG_NAME#3")
     (list "OLD_TAG_NAME#4" "NEW_TAG_NAME#4")
     (list "OLD_TAG_NAME#5" "NEW_TAG_NAME#5")
 ) )  
 ; **********************************************************************

 ; Extract selection set of all block inserts on active drawing  
 (setq ss (ssget "_X" '((0 . "INSERT"))))
 (if (/= ss nil)
   (progn
     (setq slen (sslength ss))
     (setq ix 0)
     (while (< ix slen)
       (setq blk_ent (ssname ss ix)) ; get next block insert to process        
       (setq ix (1+ ix)) ; increment for next time
       (setq enn (entnext blk_ent)) 
       (setq edd (entget enn))  
       (while (AND enn (/= (cdr (assoc 0 edd)) "SEQEND") 
                           (/= (cdr (assoc 0 edd)) "INSERT") )
         (if (= (cdr (assoc 0 edd)) "ATTRIB")
           (progn
             (setq atnam (cdr (assoc 2 edd)))
             (setq hit nil)
             (foreach x namelist
               (if (not hit)
                 (progn ; no match yet, keep processing
                   (setq matchname (car x))                
                   (if (wcmatch atnam matchname) 
                     (progn ; found exact match or wild-card match
                       ; Change name now. Substitute in new name.
                       (setq newed (subst (cons 2 (cadr x)) (assoc 2 edd) edd)) 
                       (entmod newed) ; update the title block instance
                       (entupd blk_ent) 
                       (princ "\n")
                       (princ atnam)
                       (princ " --> ")
                       (princ (cadr x))
                       (setq hit 1) ; flag that found
               ) ) ) )
             )
           )
         )     
         ; go to next sub ent in block instance and loop back up
         (if (setq enn (entnext enn)) (setq edd (entget enn))) 
     ) ) 
     (setq ss nil) ; release the selection set
   )
 )
 (princ) ; prettier
)
 

 

 

 

I love finding the answer. It makes me feel alive.:D

 

This was great to find and solved some of my problems. Is there a way to make it change attribute name only on a certain blockname?

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...