Autocad Lisp, remove all text after layer name

Autocad Lisp, remove all text after layer name

kieran.leadbetter
Advocate Advocate
2,026 Views
20 Replies
Message 1 of 21

Autocad Lisp, remove all text after layer name

kieran.leadbetter
Advocate
Advocate

Hello, I posted a similar request earlier, however this might be easier

I was hoping someone would have a lisp or know how to create one to remove all characters after a specific layer name, i.e. if my layer name was 

A200_Demolitions

But there was a variant of this within the drawing, A200_demolitions123, could I have any characters before or after the layer *A200_Demolitions* removed, and if the layer already exists once these characters are removed, can it be added to said existing layer. Got thousands of drawings I need to tidy the layers up in, and doing this manually will take me months

Kind Regards

0 Likes
2,027 Views
20 Replies
Replies (20)
Message 2 of 21

pendean
Community Legend
Community Legend
You might need a before/after list of layer names, do you have that?
And what if the new name already exists, what do you want to happen then?

LAYTRANS command is built into AutoCAD can be used for the task if the naming issues are very consistent, it has wildcard options too.
0 Likes
Message 3 of 21

Kent1Cooper
Consultant
Consultant

@kieran.leadbetter wrote:

... if my layer name was 

A200_Demolitions

But there was a variant of this within the drawing, A200_demolitions123, could I have any characters before or after the layer *A200_Demolitions* ....


Something like this, as a starting point?  Minimally tested:

(defun C:CLNN ; = Change to Layer with Nested Name
  (/ tln ss n edata)
  (setq tln (getstring "\nNested Layer Name: "))
  (if (setq ss (ssget "_X" (list (cons 8 (strcat "*" tln "*")))))
    (repeat (setq n (sslength ss)); then
      (setq edata (entget (ssname ss (setq n (1- n)))))
      (entmod (append edata (list (cons 8 tln))))
    ); repeat
    (prompt "\nNothing found on Layer(s) with appended names.")
  ); if
  (prin1)
)

You would answer your example A200_Demolitions to the prompt for the nested Layer name.  You could make a list of "base" names and apply the same functionality to each, instead of asking the User for the nested name, with a small adjustment.

If the nested Layer doesn't exist, a benefit of the appending-to-entity-data approach is it will be created in the process [with default color 7 and continuous linetype].

It doesn't get rid of the longer-name Layers, just moves things on them to the nested-name Layer.  It could be enhanced to ensure they're unlocked, etc.  LAYMRG could be used to get rid of them, but it would need to know every specific variant name involved, whereas this can find everything on variant Layers without caring exactly what the variants are.

Kent Cooper, AIA
Message 4 of 21

Sea-Haven
Mentor
Mentor
0 Likes
Message 5 of 21

kieran.leadbetter
Advocate
Advocate
I get this is probably simple coding, but there are a lot of terms within that lisp which I don't understand yet. Due to its size though I am going to use this as a thorough learning experience and research it in depth next several days, gonna be fun

How would I make a "list of base names" like you mentioned, I am attempting to make this an automatic task so I would have all our standard layers inputted into this lisp and it would tidy all the rouge layers into it

I make sure I unlock and unthaw all layers before I run any lisps and relock/rethaw afterwards so that isn't an issue.

And what do you mean by "It doesn't get rid of the longer-name Layers, just moves things on them to the nested-name Layer. "

What is the nested-name layer, would this lisp not merge any rouge layers like A200_Demolitions123... to A200_Demolitions?

Thank you aswell
0 Likes
Message 6 of 21

ВeekeeCZ
Consultant
Consultant

Possibly this could help. Locked and frozen layers are eliminated from the process.

 

;; usage
(LayerMergeToCore "*A200_Demolitions*")

(vl-load-com)

(defun LayerMergeToCore (key / :LayerList lst core)
  
  (defun :LayerList (k / d l)
    (while (setq d (tblnext "layer" (null d)))
      (if (not (or (= 1 (logand (cdr (assoc 70 d)) 1))	; thawed
		   (= 4 (logand (cdr (assoc 70 d)) 4))	; unlocked
		   (wcmatch (cdr (assoc 2 d)) "*|*")))	; not in xref
	(if (wcmatch (strcase (cdr (assoc 2 d))) (strcase k))
	  (setq l (cons (cdr (assoc 2 d)) l)))))
    l)
  
  (if (and (setq lst (:LayerList key))
	   (setq core (vl-string-trim "*" key))
	   (or (tblsearch "LAYER" core)
	       (progn
		 (command "_rename" "_la" (car lst) core)
		 (setq lst (cdr lst))))
	   (setq lst (vl-remove-if '(lambda (x) (= (strcase core) (strcase x))) lst))
	   lst
	   )
    (progn
      (command "_.LAYMRG")
      (foreach l lst (command "_Name" l))
      (command "" "_N" core "_Y"))
    (princ "\nNothing matched."))
  (princ)
  )

 

0 Likes
Message 7 of 21

Kent1Cooper
Consultant
Consultant

@kieran.leadbetter wrote:
....
How would I make a "list of base names" like you mentioned, I am attempting to make this an automatic task so I would have all our standard layers inputted into this lisp and it would tidy all the rouge layers into it
....
And what do you mean by "It doesn't get rid of the longer-name Layers, just moves things on them to the nested-name Layer. "

What is the nested-name layer, would this lisp not merge any rouge layers like A200_Demolitions123... to A200_Demolitions?
....

(setq BaseLayerNames '("A200_Demolitions" "ABC" "DEF" "XYZ" "Batman" "MarilynMonroe"))

(foreach LayName BaseLayerNames

  (.... run the same operation on that Layer Name instead of asking the User for it ....)

)

 

I mean just what it says.  The [I think you mean] rogue [not rouge] Layers remain in the drawing, but everything on them gets moved to the base-named Layer.  The reason I did that is because if the base name is "ABC", it can find things on Layers "ABC123" and "whatABCwhere" and "98ABC" and "ABCDEF" all collectively with the wildcards around the base name in the (ssget) filter -- "*ABC*".  It doesn't matter what the rogue-nesses are like -- extra characters before, after, both, etc. -- nor how many rogue Layers are involved.  Those all get put into the base-named Layer.  To eliminate those Layers using LAYMRG requires finding all those things on them and stepping through each one for its specific Layer name to apply in the command, resulting in potentially a large number of individual LAYMRG operations.  Obviously that can be done, or a different approach than object selection can be used [see @ВeekeeCZ's suggestion], with more complex code, but this was my quickie version.

 

The nested-name Layer is the one with its name in the list -- the one you want to keep.

Kent Cooper, AIA
0 Likes
Message 8 of 21

kieran.leadbetter
Advocate
Advocate
Hello, I have attempted to amend the lisp to the revision lines you replied with but I am uncertain of how to include them within the lisp.

Currently I have:

(defun C:CLNN (/ tln ss n edata)
(setq BaseLayerNames '("A200_Demolitions" "ABC" "DEF" "XYZ" "Batman" "MarilynMonroe"))
(foreach LayName BaseLayerNames
(setq tln (getstring "\nNested Layer Name: "))
(if (setq ss (ssget "_X" (list (cons 8 (strcat "*" tln "*")))))
(repeat (setq n (sslength ss)); then
(setq edata (entget (ssname ss (setq n (1- n)))))
(entmod (append edata (list (cons 8 tln))))
); repeat
(prompt "\nNothing found on Layer(s) with appended names.")
); if
)
(prin1)
)

Yet this forces the Nested Layer Name window to appear each time, so I attempted to delete the (getstring "\nNested Layer Name: ") part, but this caused a syntax issue.

Any further advice and I will try resolve it so I can learn from this, implementing list functions is new to me and seems super useful.

Kind Regards,

Also yes, I did mean Rogue not Rouge, my bad, like the use of the red for my spelling error, very clever
0 Likes
Message 9 of 21

Kent1Cooper
Consultant
Consultant

Try this [untested]:

 

(defun C:CLNN (/ BaseLayerNames ss n edata); = Change Layer to Nested Name
  (setq BaseLayerNames '("A200_Demolitions" "ABC" "DEF" "XYZ" "Batman" "MarilynMonroe"))
  (foreach LayName BaseLayerNames ; for every name in the list, do the following:
    (if (setq ss (ssget "_X" (list (cons 8 (strcat "*" LayName "*"))))); things on Layers containing listed part
      (repeat (setq n (sslength ss)); then
        (setq edata (entget (ssname ss (setq n (1- n)))))
        (entmod (append edata (list (cons 8 LayName))))
      ); repeat
      (prompt (strcat "\nNothing found on Layer(s) containing " LayName ".")); else
    ); if
  ); foreach
  (prin1)
)

 

[Of course, you don't want my list of wacky names.]

 

If you did this always in Model Space and all eligible things are always there [or as long as all eligible objects are in the current space, whatever that is], it could be simplified to just use a CHPROP command on all the things it finds, all at once, to change their Layer, without needing to step through them.  Stepping through is needed if they might occur in different spaces -- Model vs. Paper vs. different Paper Space Layouts -- because editing commands involving object selection can "see" only things in the current space.

Kent Cooper, AIA
0 Likes
Message 10 of 21

Sea-Haven
Mentor
Mentor

Just a suggestion your in good hands with Kents responses, having done similar but with around 100 layers, I used a text file containing all layer names, it can live in Excel etc just copy and paste to notepad the single column of layer names and save as a TXT file. Nice thing about using Excel is add a layer name at end then sort. Just read the text file into the variable list "BaseLayerNames".

0 Likes
Message 11 of 21

kieran.leadbetter
Advocate
Advocate
Hello, sorry for the really late reply, got taken onto another project and then I was on annual leave and a bunch of other things.

If you are still able to help me it would be much appreciated, sorry again.

When I run this lisp it just runs through all the standard layers stating

"Nothing found on Layer(s) containing A200_Demolitions.", it still doesn't merge any rogue layers back into the main standard layer. Any ideas why this would be? This is the lisp adjustments I'm using:


(defun C:CLNN (/ BaseLayerNames ss n edata); = Change Layer to Nested Name
(setq BaseLayerNames '(
"A000_BLOCK_INSERTION"
"A015_GENERAL_TEXT"
"A015_GRID_TEXT"
"A200_DEMOLITIONS"
))
(foreach LayName BaseLayerNames ; for every name in the list, do the following:
(if (setq ss (ssget "_X" (list (cons 8 (strcat "*" LayName "*"))))); things on Layers containing listed part
(repeat (setq n (sslength ss)); then
(setq edata (entget (ssname ss (setq n (1- n)))))
(entmod (append edata (list (cons 8 LayName))))
); repeat
(prompt (strcat "\nNothing found on Layer(s) containing " LayName ".")); else
); if
); foreach
(prin1)
)
Message 12 of 21

komondormrex
Mentor
Mentor

hey there,

check this one. running as (consolidate_layers '(A200_DEMOLITIONS A000_BLOCK_INSERTION A015_GENERAL_TEXT A015_GRID_TEXT)). layers locking... not checked.

 

(defun consolidate_layers (layer_list / delete_layers layers_collection)
	(foreach layer layer_list
		(if (vl-catch-all-error-p (vl-catch-all-apply 'vla-item (list (setq layers_collection 
																			(vla-get-layers 
																				(vla-get-activedocument 
																					(vlax-get-acad-object)
																				)
																			)
																	  ) 
																	  (vl-symbol-name layer)
																)
								  )
			)
				(vla-add layers_collection (vl-symbol-name layer))
		)
		(vlax-map-collection layers_collection
			'(lambda (layer_object) 
				(if (wcmatch (strcase (vla-get-name layer_object)) (strcat "*" (vl-symbol-name layer) "*"))
					(progn
						(setq layer_sset (ssget "_x" (list (cons 8 (vla-get-name layer_object)))))
						(if layer_sset
							(progn
								(foreach object (mapcar 'vlax-ename->vla-object (vl-remove-if 'listp (mapcar 'cadr (ssnamex layer_sset))))
									(vla-put-layer object (vl-symbol-name layer)) 
								)
								(setq delete_layers (append delete_layers (list layer_object))) 
							)
						)
					)
				)
			 )
		)
	)
	(foreach layer_object delete_layers
		(vl-catch-all-apply 'vla-delete (list layer_object)) 
	)
	(princ)
)

 

 

0 Likes
Message 13 of 21

kieran.leadbetter
Advocate
Advocate
Good morning, thank you and where within this lisp would I insert all the main layers I want the rogue ones to merge to?
0 Likes
Message 14 of 21

komondormrex
Mentor
Mentor

they are passed as an argument list to the function, like the following 

(consolidate_layers '(A200_DEMOLITIONS A000_BLOCK_INSERTION A015_GENERAL_TEXT A015_GRID_TEXT))

0 Likes
Message 15 of 21

kieran.leadbetter
Advocate
Advocate
Sorry I'm not that advanced with lisp or scripts, I just know how to transfer autocad commands into scripts and a few conditional things I can add to those.

I still don't understand how I add:

(consolidate_layers '(A200_DEMOLITIONS A000_BLOCK_INSERTION A015_GENERAL_TEXT A015_GRID_TEXT))

Into the lisp you sent, sorry
0 Likes
Message 16 of 21

komondormrex
Mentor
Mentor

load code i've posted.  upon success it would return to command line CONSOLIDATE_LAYERS which means the function is loaded. copy/paste the line (consolidate_layers '(A200_DEMOLITIONS A000_BLOCK_INSERTION A015_GENERAL_TEXT A015_GRID_TEXT)) to command line and hit enter. that is it.

0 Likes
Message 17 of 21

kieran.leadbetter
Advocate
Advocate
Ah that makes more sense, I will try it now, is it possible to enclose the layers with "Layer" incase any layers contain a space within them?
0 Likes
Message 18 of 21

kieran.leadbetter
Advocate
Advocate
Cool so this partially works, I have 2 issues currently when using it however.

First one is the command somehow needs to be implemented within the lisp itself, as I have 135 layers to Consolidate and it surpassing the autocad command line character limit

It also still does not merge any rogue layers containing the main layers name to the main layer, it just creates the layer if it does not already exist
0 Likes
Message 19 of 21

Kent1Cooper
Consultant
Consultant

@kieran.leadbetter wrote:
.... When I run this lisp it just runs through all the standard layers stating
"Nothing found on Layer(s) containing A200_Demolitions."....

I set up a simpler situation, with "base" Layer names "ABC" and "DEF" and some "rogue" Layer names having extra characters either before or after the base three letters, or both, like "ABC123" and "4DEF5".  That simpler base Layer name list was the only change I made in your code in Message 11, and it worked for me -- all objects on the rogue Layers got changed to the corresponding base Layers.  Are you sure you spelled everything right?  [You have powerful-long Layer names, giving greater opportunity for typos.]  Are any of your Layers locked?  [It shouldn't be case-sensitive, but have you tried it with full letter-case agreement?]

 

But no, so far it doesn't eliminate the rogue Layers, but only empties them [that is, top-level objects on them -- I didn't get into nested objects yet].  I'd want to get the consolidating working before going on to the elimination of Layers [which could be by PURGE if everything's top-level, rather than LAYDEL or LAYMRG].

Kent Cooper, AIA
Message 20 of 21

komondormrex
Mentor
Mentor

you mean a dwg to process has 135 stationary layers plus other layers with prefixes/suffixes to each stationary layer?

0 Likes