shailujp Posted November 18, 2022 Posted November 18, 2022 (edited) Hello all, I have got about 10 drawing with 100s of attribute named "LINE" in each file which has characters like this 65-CHWS-202XXX-C1A I want to modify each XXX character to 001, 002, 003 etc. keeping all other characters as is. Lee Mac (The Legend) made me below posted code some years back which incremented the whole text which worked wonderfully well for me so far. But now I want to modify just a few characters from the full text. Could anyone help me on this? (defun c:INCATT3 ( / tag pre ss1 ) (vl-load-com) (setq tag "LINE" pre "") (if (setq *num* (cond ( (getint (strcat "\nSpecify Starting Number" (if *num* (strcat " <" (itoa *num*) "> : ") ": ")))) ( *num* ))) (while (setq ss1 (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (vl-some (function (lambda ( x ) (if (eq tag (vla-get-tagstring x)) (not (vla-put-textstring x (strcat pre (itoa *num*)))) ) ) ) (vlax-invoke (vlax-ename->vla-object (ssname ss1 0)) 'getattributes) ) (setq *num* (1+ *num*)) (princ (strcat tag " Attribute not found.")) ) ) ) (princ) ) Sample file.dwg Edited November 18, 2022 by shailujp Added sample AutoCAD file Quote
Steven P Posted November 18, 2022 Posted November 18, 2022 (edited) Is this change any good? (works if the characters are the same for each line I think) (defun c:INCATT3 ( / tag pre ss1 ) (vl-load-com) (setq tag "LINE" pre "") ;;;New Bit (setq prefx (getstring "\nspecify Prefix String: ")) (setq suffx (getstring "\nspecify Suffix String: ")) ;;;End New Bit (if (setq *num* (cond ( (getint (strcat "\nSpecify Starting Number" (if *num* (strcat " <" (itoa *num*) "> : ") ": ")))) ( *num* ))) (while (setq ss1 (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (vl-some (function (lambda ( x ) (if (eq tag (vla-get-tagstring x)) ;;Modified Line (not (vla-put-textstring x (strcat pre prefx (itoa *num*) suffx))) ;;End modified line ) ) ) (vlax-invoke (vlax-ename->vla-object (ssname ss1 0)) 'getattributes) ) (setq *num* (1+ *num*)) (princ (strcat tag " Attribute not found.")) ) ) ) (princ) ) Edited November 18, 2022 by Steven P Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 Use ATTOUT to mass change attribute values with excel. then ATTIN when you want to update the drawing. Quote
shailujp Posted November 18, 2022 Author Posted November 18, 2022 (edited) 41 minutes ago, Steven P said: Is this change any good? (works if the characters are the same for each line I think) (defun c:INCATT3 ( / tag pre ss1 ) (vl-load-com) (setq tag "LINE" pre "") ;;;New Bit (setq prefx (getstring "\nspecify Prefix String: ")) (setq suffx (getstring "\nspecify Suffix String: ")) ;;;End New Bit (if (setq *num* (cond ( (getint (strcat "\nSpecify Starting Number" (if *num* (strcat " <" (itoa *num*) "> : ") ": ")))) ( *num* ))) (while (setq ss1 (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (vl-some (function (lambda ( x ) (if (eq tag (vla-get-tagstring x)) ;;Modified Line (not (vla-put-textstring x (strcat pre prefx (itoa *num*) suffx))) ;;End modified line ) ) ) (vlax-invoke (vlax-ename->vla-object (ssname ss1 0)) 'getattributes) ) (setq *num* (1+ *num*)) (princ (strcat tag " Attribute not found.")) ) ) ) (princ) ) Hi Seven, Unfortunately, it doesn't work for my requirement. It asks for prefix and suffix which are different for each line. And the number of characters would also be longer if there are 3 digits at front (eg. 200-CHWS-202XXX-C1A) . The only constant is "XXX" in each line. Is there anyway the utility can just target these 3 characters? I have edited the original post to add the sample AutoCAD file for reference. Edited November 18, 2022 by shailujp 1 Quote
shailujp Posted November 18, 2022 Author Posted November 18, 2022 7 minutes ago, mhupp said: Use ATTOUT to mass change attribute values with excel. then ATTIN when you want to update the drawing. It will work for sure, but I suspect it would require more work to take the data out, fix them in excel and then put it back. (I have edited the original post to add the sample AutoCAD file for reference). Quote
Steven P Posted November 18, 2022 Posted November 18, 2022 (edited) Thought you would want it the harder way... still got to give me credit for taking a chance you wanted the easy way..... Often the easiest way I find if the texts are various length before or after the text to change and that text is the same for all is to use Lee Macs String to List - using the incremental text as the delimitator. In your case, string to list, with 'XXX' deliminator. Here you get a list returned, so grab the first item as the prefix, and the 2nd as the suffix... if that makes sense? Try this way: (defun c:INCATT3 ( / tag pre ss1 ) (vl-load-com) (defun LM:getattributevalue ( blk tag / enx ) ;; refer to Lee Mac Website (if (and (setq blk (entnext blk)) (= "ATTRIB" (cdr (assoc 0 (setq enx (entget blk)))))) (if (= (strcase tag) (strcase (cdr (assoc 2 enx)))) (cdr (assoc 1 (reverse enx))) (LM:getattributevalue blk tag) ) ) ) (defun LM:str->lst ( str del / pos ) ;; refer to Lee Mac Website (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del)) (list str) ) ) (setq tag "LINE" pre "") (if (setq *num* (cond ( (getint (strcat "\nSpecify Starting Number" (if *num* (strcat " <" (itoa *num*) "> : ") ": ")))) ( *num* ))) (while (setq ss1 (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) ;; added line (setq tagstring (LM:getattributevalue (ssname ss1 0) tag)) (if (vl-some (function (lambda ( x ) (if (eq tag (vla-get-tagstring x)) ;;Modified part (progn (setq strtolst (LM:str->lst tagstring "XXX")) (setq prefx (nth 0 strtolst)) (setq suffx (nth 1 strtolst)) (not (vla-put-textstring x (strcat pre prefx (itoa *num*) suffx))) ) ; end progn ;end modified part ) ) ) (vlax-invoke (vlax-ename->vla-object (ssname ss1 0)) 'getattributes) ) (setq *num* (1+ *num*)) (princ (strcat tag " Attribute not found.")) ) ) ) (princ) ) So problems with this you might want to look at: If your text string doesn't have 'XXX' in it, the list to string returns a list of 1 item, and then fail since there is no suffix to use.. a fix with an 'if' I think For future versatility you might also want to add some functions to change / specify the tag to use and also to enter the base text to increment (the 'XXX') EDIT Also might want to consider if the user enters leading zeros, the above will remove them - 001 becomes 1 in the increment Edited November 18, 2022 by Steven P Quote
shailujp Posted November 18, 2022 Author Posted November 18, 2022 19 minutes ago, Steven P said: Thought you would want it the harder way... still got to give me credit for taking a chance you wanted the easy way..... Often the easiest way I find if the texts are various length before or after the text to change and that text is the same for all is to use Lee Macs String to List - using the incremental text as the delimitator. In your case, string to list, with 'XXX' deliminator. Here you get a list returned, so grab the first item as the prefix, and the 2nd as the suffix... if that makes sense? Try this way: (defun c:INCATT3 ( / tag pre ss1 ) (vl-load-com) (defun LM:getattributevalue ( blk tag / enx ) ;; refer to Lee Mac Website (if (and (setq blk (entnext blk)) (= "ATTRIB" (cdr (assoc 0 (setq enx (entget blk)))))) (if (= (strcase tag) (strcase (cdr (assoc 2 enx)))) (cdr (assoc 1 (reverse enx))) (LM:getattributevalue blk tag) ) ) ) (defun LM:str->lst ( str del / pos ) ;; refer to Lee Mac Website (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del)) (list str) ) ) (setq tag "LINE" pre "") (if (setq *num* (cond ( (getint (strcat "\nSpecify Starting Number" (if *num* (strcat " <" (itoa *num*) "> : ") ": ")))) ( *num* ))) (while (setq ss1 (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) ;; added line (setq tagstring (LM:getattributevalue (ssname ss1 0) tag)) (if (vl-some (function (lambda ( x ) (if (eq tag (vla-get-tagstring x)) ;;Modified part (progn (setq strtolst (LM:str->lst tagstring "XXX")) (setq prefx (nth 0 strtolst)) (setq suffx (nth 1 strtolst)) (not (vla-put-textstring x (strcat pre prefx (itoa *num*) suffx))) ) ; end progn ;end modified part ) ) ) (vlax-invoke (vlax-ename->vla-object (ssname ss1 0)) 'getattributes) ) (setq *num* (1+ *num*)) (princ (strcat tag " Attribute not found.")) ) ) ) (princ) ) So problems with this you might want to look at: If your text string doesn't have 'XXX' in it, the list to string returns a list of 1 item, and then fail since there is no suffix to use.. a fix with an 'if' I think For future versatility you might also want to add some functions to change / specify the tag to use and also to enter the base text to increment (the 'XXX') EDIT Also might want to consider if the user enters leading zeros, the above will remove them - 001 becomes 1 in the increment Regardless of this is done easy way or the hard way, credit is all yours, Steven. My knowledge is very limited being a newbie in LISP world (often a user of the code than a creator). So I don't understand fully what all you mentioned above, and would not understand clearly what is required now and what it does to future requirements. Sincere apologies. But the last line makes good sense, and after trying your code, I realized that 001 indeed became 1 and that's an issue for me. Because, I am told that 001 is required to keep the 6 digits in the middle. Can this be fixed to keep 3 digits always (001, 009, 010 etc)? I didn't think this clearly earlier. 1 Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 (edited) Crap overwritten alot of stuff but RonjonP showed me this to access block values ;; Look into get\setpropertyvalue .. pretty powerful ;; https://help.autodesk.com/view/ACD/2023/ENU/?guid=GUID-8E5913FC-09ED-4C70-AFB7-2431C062E899 (setq string or # (getpropertyvalue ename "LINE NO") getpropertyvalue doesn't work in BricsCAD so i cant test this. this should allow you to select multiple blocks at once and just step thought them. probably need to setup a way to sort them so you know what order they will be in. ;;multi select without sort (defun c:INCATT3 ( / num tag pre ss1 ) (vl-load-com) (if (and (setq *num* (getint (strcat "\nSpecify Starting Number"))) (setq num (AT:NumFix *num* 3)) (setq ss (ssget "_L" '((0 . "INSERT") (66 . 1)))) ) (foreach blk (vl-remove-if 'listp (mapcar 'cadr (ssnamex ss))) (if (and (setq tagstring (getpropertyvalue blk "LINE")) (setq n (vl-string-search "202XXX" tagstring))) ;if block has line no as an attribuet (setpropertyvalue (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n 6)))) ;and "202XXX" is prestent in the string (princ "\"LINE NO\" Attribute not found.") ;update value to new name ) (setq *num* (1+ *num*)) (setq num (AT:NumFix *num* 3)) ) ) (princ) ) (defun AT:NumFix (s n) ;; Fix number string with leading zeros ;; s - Number string to fix ;; n - Number of characters for final string ;; Alan J. Thompson, 10.29.09 ;; (AT:NumFix i 3) i= 1 = 001 (if (< (strlen s) n) (AT:NumFix (strcat "0" s) n) s ) ) Edited November 18, 2022 by mhupp 1 Quote
shailujp Posted November 18, 2022 Author Posted November 18, 2022 20 minutes ago, mhupp said: Here is some code to help. (setq i (1+ i)) (setq num (strcat "202" (AT:NumFix i 3))) ... (defun AT:NumFix (s n) ;; Fix number string with leading zeros ;; s - Number string to fix ;; n - Number of characters for final string ;; Alan J. Thompson, 10.29.09 ;; (AT:NumFix i 3) i= 1 = 001 (if (< (strlen s) n) (AT:NumFix (strcat "0" s) n) s ) ) Also its easy to then calculate the new name using existing and not asking for prefix sufix. (setq new (strcat (substr str 1 (setq n (vl-string-search "202XXX" str))) *new name 202### calculated with 202 + NumFix* (substr str (+ n 6)))) "200-CHWS-202XXX-C1A" would be split up into 3 strings and strcat would join them together. "200-CHWS-" + "202001" + "-C1A" after starcat "200-CHWS-202001-C1A" Hi mhupp, I am unable to use the code you posted. I am getting this error. "; error: bad argument type: numberp: nil" Was I supposed to combine these two codes in one LISP file? Could you please help me on this? Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 No i was editing it delete most of what i posted the code should work now. Quote
shailujp Posted November 18, 2022 Author Posted November 18, 2022 22 minutes ago, mhupp said: No i was editing it delete most of what i posted the code should work now. I am still unable to run the code properly. It gives an error Command: INCATT3 Specify Starting Number123 ; error: bad argument type: stringp 123 Quote getpropertyvalue doesn't work in BricsCAD so i cant test this. this should allow you to select multiple blocks at once and just step thought them. probably need to setup a way to sort them so you know what order they will be in. Little confused by your comment above. I am not supposed to select the block prior, I want to select them once I enter the starting number, and then each block I select should keep on incrementing. Is this what your code does? Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 (edited) This goes back to selecting one at a time. if you input 15 for starting number it will spit out "015" and if you select a block that has attribute "LINE" = "50-CHWS-202XXX-C1A" it should change to "50-CHWS-202015-C1A" (defun c:INCATT3 ( / num tag pre ss1 ) (vl-load-com) (if (and (setq i (getint "\nSpecify Starting Number")) (setq replace "202XXX") (setq l (1+ (strlen replace))) ) (progn (setq num (AT:NumFix (itoa i) 3)) ;convert inter to sring before selection (while (setq ss (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (and (setq tagstring (getpropertyvalue (ssname ss 0) "LINE")) (setq n (vl-string-search replace tagstring))) ;if block has ATTRIBUTE line and contains (progn ;the string "202XXX" update to new string (setpropertyvalue (ssname ss 0) "LINE" (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l)))) (setq i (1+ i)) (setq num (AT:NumFix (itoa i) 3)) ) (princ "\"LINE\" Attribute not found or doesn't contain \"202XXX\"") ) ) ) ) (princ) ) (defun AT:NumFix (s n) ;; Fix number string with leading zeros ;; s - Number string to fix ;; n - Number of characters for final string ;; Alan J. Thompson, 10.29.09 ;; (AT:NumFix i 3) i= 1 = 001 (if (< (strlen s) n) (AT:NumFix (strcat "0" s) n) s ) ) --edit 2 hours ago, shailujp said: Little confused by your comment above. I am not supposed to select the block prior, I want to select them once I enter the starting number, and then each block I select should keep on incrementing. Is this what your code does? You could select multiple blocks at once and sort them left to right or top to bottom so you know what order they will update in. rather then one at a time. but one at a time is less prone to errors. Edited November 18, 2022 by mhupp updated code Quote
Steven P Posted November 18, 2022 Posted November 18, 2022 (edited) ..... (setq num (AT:NumFix (itoa i) 3)) ..... Only sayin'..... I am getting an "; error: ADS request error" error, think it is from (setpropertyvalue (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l)))) ? Not quite right but should it be more like (there was a while loop bracket out of place too): (defun c:INCATT3 ( / num tag pre ss1 ) (vl-load-com) (if (and (setq i (getint "\nSpecify Starting Number")) (setq replace "202XXX") (setq l (strlen replace)) ) (progn (setq num (AT:NumFix (itoa i) 3)) ;convert inter to sring before selection (while (setq ss (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (and (setq tagstring (getpropertyvalue (ssname ss 0) "LINE")) (setq n (vl-string-search replace tagstring))) ;if block has ATTRIBUTE line and contains (setpropertyvalue (ssname ss 0) "LINE" (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l)))) ;the string "202XXX" update to new string (princ "\"LINE\" Attribute not found or doesn't contain \"202XXX\"") ) (setq i (1+ i)) (setq num (AT:NumFix (itoa i) 3)) ) ) ) (princ) ) Edited November 18, 2022 by Steven P 1 Quote
Steven P Posted November 18, 2022 Posted November 18, 2022 A bit longer than MHUPP, added a couple of bits in and blatently stolen 'ATs' fixnump If you select an attribute without the XXX text in it, it will continue OK - noting it will also increment the number on the assumption you clicked the non XXX text wanting it to have the next number in it.... can change it if needed (defun c:INCATT3 ( / tag pre ss1 ) (vl-load-com) (defun LM:getattributevalue ( blk tag / enx ) ;; refer to Lee Mac Website (if (and (setq blk (entnext blk)) (= "ATTRIB" (cdr (assoc 0 (setq enx (entget blk)))))) (if (= (strcase tag) (strcase (cdr (assoc 2 enx)))) (cdr (assoc 1 (reverse enx))) (LM:getattributevalue blk tag) ) ) ) (defun LM:str->lst ( str del / pos ) ;; refer to Lee Mac Website (if (setq pos (vl-string-search del str)) (cons (substr str 1 pos) (LM:str->lst (substr str (+ pos 1 (strlen del))) del)) (list str) ) ) (defun AT:NumFix (s n) ;; Fix number string with leading zeros ;; s - Number string to fix ;; n - Number of characters for final string ;; Alan J. Thompson, 10.29.09 ;; (AT:NumFix i 3) i= 1 = 001 (if (< (strlen s) n) (AT:NumFix (strcat "0" s) n) s ) ) (setq tag "LINE" pre "") (if (setq *num* (cond ( (getint (strcat "\nSpecify Starting Number" (if *num* (strcat " <" (itoa *num*) "> : ") ": ")))) ( *num* ))) (while (setq ss1 (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) ;; added line (setq tagstring (LM:getattributevalue (ssname ss1 0) tag)) (if (vl-some (function (lambda ( x ) (if (eq tag (vla-get-tagstring x)) ;;Modified part (progn (setq strtolst (LM:str->lst tagstring "XXX")) (if (= (length strtolst) 1) () (progn (setq prefx (nth 0 strtolst)) (setq suffx (nth 1 strtolst)) (not (vla-put-textstring x (strcat pre prefx (AT:NumFix (itoa *num*) 3) suffx))) ) ; end progn ) ' end if ) ; end progn ;end modified part ) ) ) (vlax-invoke (vlax-ename->vla-object (ssname ss1 0)) 'getattributes) ) (setq *num* (1+ *num*)) (princ (strcat tag " Attribute not found.")) ) ) ) (princ) ) 1 Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 13 minutes ago, Steven P said: I am getting an "; error: ADS request error" error, think it is from (setpropertyvalue (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l)))) ? Yeah can't test code but was leaving out the entname so it should work now (setpropertyvalue (ssname ss 0) (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l)))) 1 Quote
Steven P Posted November 18, 2022 Posted November 18, 2022 8 minutes ago, mhupp said: Yeah can't test code but was leaving out the entname so it should work now (setpropertyvalue (ssname ss 0) (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l)))) Nice. Looks like you needed the tag name in there too - see below. I was getting an extra 'X' at the end of the string, so a slight change adding 1 to the (tagstring (+ n l 1)) (defun c:INCATT3 ( / num tag pre ss1 ) (vl-load-com) (if (and (setq i (getint "\nSpecify Starting Number")) (setq replace "202XXX") (setq l (strlen replace)) ) (progn (setq num (AT:NumFix (itoa i) 3)) ;convert inter to sring before selection (while (setq ss (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (and (setq tagstring (getpropertyvalue (ssname ss 0) "LINE")) (setq n (vl-string-search replace tagstring))) ;if block has ATTRIBUTE line and contains (setpropertyvalue (ssname ss 0) "LINE" (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l 1)))) ;the string "202XXX" update to new string (princ "\"LINE\" Attribute not found or doesn't contain \"202XXX\"") ) (setq i (1+ i)) (setq num (AT:NumFix (itoa i) 3)) ) ) ) (princ) ) (defun AT:NumFix (s n) ;; Fix number string with leading zeros ;; s - Number string to fix ;; n - Number of characters for final string ;; Alan J. Thompson, 10.29.09 ;; (AT:NumFix i 3) i= 1 = 001 (if (< (strlen s) n) (AT:NumFix (strcat "0" s) n) s ) ) 1 Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 (edited) Noooice Just wished it worked in BricsCAD. maybe it does in the newer version. added the 1+ when calculating the l Edited November 18, 2022 by mhupp 1 Quote
mhupp Posted November 18, 2022 Posted November 18, 2022 (edited) Changed the code again noticed it would would rev up "i" even if you selected a block that didn't match the two if statements. So put these two lines to run if the statement is true . Rather then just wrapped in the while statement. (setq i (1+ i)) (setq num (AT:NumFix (itoa i) 3)) Edited November 18, 2022 by mhupp 1 Quote
shailujp Posted November 19, 2022 Author Posted November 19, 2022 (edited) 11 hours ago, Steven P said: Nice. Looks like you needed the tag name in there too - see below. I was getting an extra 'X' at the end of the string, so a slight change adding 1 to the (tagstring (+ n l 1)) (defun c:INCATT3 ( / num tag pre ss1 ) (vl-load-com) (if (and (setq i (getint "\nSpecify Starting Number")) (setq replace "202XXX") (setq l (strlen replace)) ) (progn (setq num (AT:NumFix (itoa i) 3)) ;convert inter to sring before selection (while (setq ss (ssget "_+.:E:S:L" '((0 . "INSERT") (66 . 1)))) (if (and (setq tagstring (getpropertyvalue (ssname ss 0) "LINE")) (setq n (vl-string-search replace tagstring))) ;if block has ATTRIBUTE line and contains (setpropertyvalue (ssname ss 0) "LINE" (strcat (substr tagstring 1 n) "202" num (substr tagstring (+ n l 1)))) ;the string "202XXX" update to new string (princ "\"LINE\" Attribute not found or doesn't contain \"202XXX\"") ) (setq i (1+ i)) (setq num (AT:NumFix (itoa i) 3)) ) ) ) (princ) ) (defun AT:NumFix (s n) ;; Fix number string with leading zeros ;; s - Number string to fix ;; n - Number of characters for final string ;; Alan J. Thompson, 10.29.09 ;; (AT:NumFix i 3) i= 1 = 001 (if (< (strlen s) n) (AT:NumFix (strcat "0" s) n) s ) ) Hi Steven, your code works perfectly for my needs. Thank you so much for your time and help. Much appreciated! Edited November 19, 2022 by shailujp 1 Quote
shailujp Posted November 19, 2022 Author Posted November 19, 2022 9 hours ago, mhupp said: Changed the code again noticed it would would rev up "i" even if you selected a block that didn't match the two if statements. So put these two lines to run if the statement is true . Rather then just wrapped in the while statement. (setq i (1+ i)) (setq num (AT:NumFix (itoa i) 3)) Hi mhupp, your code works perfectly for my needs. It would save a lot of time for me. Thank you so much for your time and help. Much appreciated! 1 Quote
Recommended Posts
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.