TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: V-Man on December 08, 2010, 09:12:35 AM

Title: Replace part of attribute
Post by: V-Man on December 08, 2010, 09:12:35 AM

Can some show me how to replace only part of an attribute? For instance, "3021920" is an attribute and I want to change "30" to "GF" but leave the rest of the attribute as is so the final result would be "GF21920". I have numerous blocks with this and I need a simplified way to globally make the change. Any help appreciated.

Thanks
Title: Re: Replace part of attribute
Post by: CAB on December 08, 2010, 09:21:26 AM
I thought  Lee or Tim had a "Find and Replace" that worked on attributes and allowed wild cards.
(Replace "30*" "GF")

But you may need to use the block name and / or attribute Tag Name as a filter too to prevent text from getting hit.


Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 09:30:57 AM
Something like this?

Code: [Select]
(defun c:test ( / *error* RegEx ss ) (vl-load-com)
  ;; © Lee Mac 2010

  (defun *error* ( msg )
    (LM:ReleaseObject RegEx)
    (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
        (princ (strcat "\n** Error: " msg " **")))
    (princ)
  )

  (if (ssget "_X" '((0 . "INSERT") (66 . 1)))
    (progn
      (setq RegEx (vlax-create-object "VBScript.RegExp"))

      (mapcar '(lambda ( x ) (vlax-put-property RegEx (car x) (cdr x)))
        (list
          (cons 'pattern  "^30(.*)")
          (cons 'global     acfalse)
          (cons 'ignorecase acfalse)
        )
      )
     
      (vlax-for obj
        (setq ss
          (vla-get-ActiveSelectionSet
            (vla-get-ActiveDocument (vlax-get-acad-object))
          )
        )

        (mapcar
          (function
            (lambda ( a / s n )
              (if (not (eq (setq s (vla-get-TextString a))
                           (setq n (vlax-invoke RegEx 'replace s "GF$1"))))

                (vla-put-TextString a n)
              )
            )
          )
          (vlax-invoke obj 'GetAttributes)
        )
      )

      (vla-delete ss)
      (LM:ReleaseObject RegEx)
    )
  )

  (princ)
)

;;------------------=={ Release Object }==--------------------;;
;;                                                            ;;
;;  Releases a VLA Object from memory via plentiful error     ;;
;;  trapping                                                  ;;
;;------------------------------------------------------------;;
;;  Author: Lee Mac, Copyright © 2010 - www.lee-mac.com       ;;
;;------------------------------------------------------------;;
;;  Arguments:                                                ;;
;;  obj - VLA Object to be released from memory               ;;
;;------------------------------------------------------------;;
;;  Returns:  T if Object Released, else nil                  ;;
;;------------------------------------------------------------;;

(defun LM:ReleaseObject ( obj ) (vl-load-com)
  ;; © Lee Mac 2010
  (and obj (eq 'VLA-OBJECT (type obj)) (not (vlax-object-released-p obj))
    (not
      (vl-catch-all-error-p
        (vl-catch-all-apply
          (function vlax-release-object) (list obj)
        )
      )
    )
  )
)


EDIT:  Had it the wrong way round ...
Title: Re: Replace part of attribute
Post by: GDF on December 08, 2010, 11:42:48 AM
Lee

I can make use of this.

Quick question, how would I update all patterns containing the following:
          (cons 'pattern  "^1-1-1-1(.*)")
          (cons 'pattern  "^2-1-1-1(.*)")
          (cons 'pattern  "^2-1-3-1(.*)")         
within one the same argument of the routine?
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 11:50:22 AM
I would say use:

Code: [Select]
"^[12]-1-[13]-1(.*)"
but this would include:

Code: [Select]
"^1-1-3-1(.*)"

among others.
Title: Re: Replace part of attribute
Post by: GDF on December 08, 2010, 12:09:15 PM
Thanks Lee

I can use this routine to update my room name with floor finsh block. I would replace all of the floor finishes:
1-1-1-1, 2-1-3-1 and so on with a blank setting.

(cons 'pattern  "^[123456]-[123456]-[123456]-[123456](.*)")

(setq n (vlax-invoke RegEx 'replace s "$1"))))

This is really neat, a simple way to update all of the floor finishes with a unit or building plan with a (nil) finishes, but still keepig the block room names intact.

Thanks
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 12:13:15 PM
You're welcome Gary, glad you could get some use out of it  :-)

You could replace:

Code: [Select]
(cons 'pattern  "^[123456]-[123456]-[123456]-[123456](.*)")
With:

Code: [Select]
(cons 'pattern  "^[1-6]-[1-6]-[1-6]-[1-6](.*)")
to achieve the same result. 

Reference here (http://msdn.microsoft.com/en-us/library/f97kw5ka%28v=VS.85%29.aspx)  :-)
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 12:15:53 PM
I can use this routine to update my room name with floor finsh block. I would replace all of the floor finishes:
1-1-1-1, 2-1-3-1 and so on with a blank setting

By 'blanking' do you mean setting the attribute to an empty string?  ( "" )

If so, this could be done using wcmatch:

Code: [Select]
(if (wcmatch (vla-get-TextString a) "[1-6]-[1-6]-[1-6]-[1-6]*")
  (vla-put-TextString a "")
)

And you wouldn't need to go the RegExp route.
Title: Re: Replace part of attribute
Post by: GDF on December 08, 2010, 12:24:27 PM
Yes, "" is my blank

How would you modify it to include all characters, for example:
1-1(2)-4-1
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 12:29:17 PM
I'm not sure what you mean by 'all characters', but maybe some combination of this?

Code: [Select]
(defun c:test ( / ss ) (vl-load-com)
  ;; © Lee Mac 2010

  (if (ssget "_X" '((0 . "INSERT") (66 . 1)))
    (progn     
      (vlax-for obj
        (setq ss
          (vla-get-ActiveSelectionSet
            (vla-get-ActiveDocument (vlax-get-acad-object))
          )
        )
        (mapcar
          (function
            (lambda ( a / s n )
              (if (wcmatch (vla-get-TextString a) "[color=red]#-*-#-#*[/color]")
                (vla-put-TextString a "")
              )
            )
          )
          (vlax-invoke obj 'GetAttributes)
        )
      )
      (vla-delete ss)
    )
  )
  (princ)
)

If need be, you could also add extra conditions on the attribute involving the Tag String.
Title: Re: Replace part of attribute
Post by: GDF on December 08, 2010, 12:32:27 PM
Wow, now that is kool.

I should have said any character.
That did the job.

I have got to lean this vla-complictedstuff and wildcards.

Thanks again
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 12:46:48 PM
Thanks Gary :-)

The VLIDE has quite a good entry on wcmatch, certainly enough to help you understand my example above  :-)
Title: Re: Replace part of attribute
Post by: ronjonp on December 08, 2010, 05:42:24 PM
You're welcome Gary, glad you could get some use out of it  :-)

You could replace:

Code: [Select]
(cons 'pattern  "^[123456]-[123456]-[123456]-[123456](.*)")
With:

Code: [Select]
(cons 'pattern  "^[1-6]-[1-6]-[1-6]-[1-6](.*)")
to achieve the same result. 

Reference here (http://msdn.microsoft.com/en-us/library/f97kw5ka%28v=VS.85%29.aspx)  :-)

That RexExp is some cool schtuff  :-)
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 05:56:33 PM
That RexExp is some cool schtuff  :-)

Definitely  :-)
Title: Re: Replace part of attribute
Post by: GDF on December 08, 2010, 06:35:14 PM
Thanks again you guys, I can make good use of this routine.

Modified it to cover many different combinations:

Code: [Select]
(defun ARCH:Finish (1st 2nd / *error* ss ) (vl-load-com)
  ;; © Lee Mac 2010 
  (defun *error* ( msg )
    (or (wcmatch (strcase msg) "*BREAK,*CANCEL*,*EXIT*")
        (princ (strcat "\n** Error: " msg " **")))
    (princ)
  )
  (if (ssget "_X" '((0 . "INSERT") (66 . 1)))
    (progn     
      (vlax-for obj
        (setq ss
          (vla-get-ActiveSelectionSet
            (vla-get-ActiveDocument (vlax-get-acad-object))
          )
        )
        (mapcar
          (function
            (lambda ( a / s n )
              (if (wcmatch (vla-get-TextString a) 1st)
                (vla-put-TextString a 2nd)
              )
            )
          )
          (vlax-invoke obj 'GetAttributes)
        )
      )
      (vla-delete ss)
    )
  )
  (princ)
)
(defun c:TileFinish ()(ARCH:Finish "2-1-1-1" "4-1-1-1"))
(defun c:VCTFinish ()(ARCH:Finish "4-1-1-1" "2-1-1-1"))
(defun c:HallcarpetFinish ()(ARCH:Finish "3-*-1-1" "1-1(4)-1-1"))
(defun c:HallconcreteFinish ()(ARCH:Finish "1-*-1-1" "3-1(4)-1-1"))
(defun c:RoomFinishNil ()(ARCH:Finish "#-*-#-#*" ""))
Title: Re: Replace part of attribute
Post by: Lee Mac on December 08, 2010, 06:39:37 PM
Nice one Gary, I like it  :-)
Title: Re: Replace part of attribute
Post by: CAB on December 09, 2010, 08:29:17 AM
Just being picky but s and n seem to be artifacts, no?

Code: [Select]
            (lambda ( a /[color=red] s n [/color])
              (if (wcmatch (vla-get-TextString a) 1st)
                (vla-put-TextString a 2nd)
              )
            )
Title: Re: Replace part of attribute
Post by: Lee Mac on December 09, 2010, 08:32:12 AM
Just being picky but s and n seem to be artifacts, no?

Good catch Alan  :-)
Title: Re: Replace part of attribute
Post by: Pad on December 09, 2010, 10:55:16 AM
I'm glad I saw this thread.
I've been having a problem blanking null value attributes since upgrading autocad.  In 2005 I could use find and then replace with nothing.
Since upgrading to 2009 you can't replace with nothing, a value has to be entered in the "replace with" box.

but
(defun c:nv ()(nullvalues "-999.00" ""))
works a treat thanks Lee and GDF!