C. Roberts Posted August 20 Posted August 20 In my lisp I need it to look for a block name that starts with "DTBLK" and could have more than 1 character at the end. Currently I have it written as shown below only going to "Z" but it could have 2 characters after "DTBLK". Is there a way to use a wildcard or some other function to shorten this down? I have similar situations multiple times in the lisp that could benefit from this as well. ((and (tblsearch "BLOCK" "ANCHOR") (tblsearch "BLOCK" "RNOTES") (or (tblsearch "BLOCK" "DTBLKA") (tblsearch "BLOCK" "DTBLKB") (tblsearch "BLOCK" "DTBLKC") (tblsearch "BLOCK" "DTBLKD") (tblsearch "BLOCK" "DTBLKE") (tblsearch "BLOCK" "DTBLKF") (tblsearch "BLOCK" "DTBLKG") (tblsearch "BLOCK" "DTBLKH") (tblsearch "BLOCK" "DTBLKI") (tblsearch "BLOCK" "DTBLKJ") (tblsearch "BLOCK" "DTBLKK") (tblsearch "BLOCK" "DTBLKL") (tblsearch "BLOCK" "DTBLKM") (tblsearch "BLOCK" "DTBLKN") (tblsearch "BLOCK" "DTBLKO") (tblsearch "BLOCK" "DTBLKP") (tblsearch "BLOCK" "DTBLKQ") (tblsearch "BLOCK" "DTBLKR") (tblsearch "BLOCK" "DTBLKS") (tblsearch "BLOCK" "DTBLKT") (tblsearch "BLOCK" "DTBLKU") (tblsearch "BLOCK" "DTBLKV") (tblsearch "BLOCK" "DTBLKW") (tblsearch "BLOCK" "DTBLKX") (tblsearch "BLOCK" "DTBLKY") (tblsearch "BLOCK" "DTBLKZ"))) Thank you!! Quote
pkenewell Posted August 20 Posted August 20 (edited) @C. Roberts Something like this? Minimal testing done, but works for me. ; Start a list with the name of the first block. (setq bl (list (cdr (assoc 2 (tblnext "BLOCK" T))))) ; add all the other block names. (while (setq b (tblnext "BLOCK")) (setq bl (cons (cdr (assoc 2 b)) bl)) ) ; conditional test for block names "ANCHOR", "RNOTES", and search for and "DTBLK" with 1 or 2 Alpha chracters on the end. ; note - it could just be "DTBLK*" in the wcmatch if it doesn't matter what the suffix is. (and (tblsearch "BLOCK" "ANCHOR") (tblsearch "BLOCK" "RNOTES") (> (length (vl-remove-if '(lambda (y)(= y nil)) (mapcar '(lambda (x)(wcmatch x "DTBLK@, DTBLK@@")) bl ) ) ) 0 ) ) Edited August 20 by pkenewell Quote
Tsuky Posted August 20 Posted August 20 A bit similar to @pkenewell ((lambda ( / flag tbl) (setq flag T) (while (setq tbl (tblnext "BLOCK" flag)) (cond ((wcmatch (cdr (assoc 2 tbl)) "ANCHOR,RNOTES,DTBLK*") (princ (strcat "\n\"" (cdr (assoc 2 tbl)) "\" found")) ) ) (setq flag nil) ) (prin1) )) 1 Quote
pkenewell Posted August 20 Posted August 20 (edited) 1 hour ago, Tsuky said: A bit similar to @pkenewell @Tsuky Nice - that's a bit shorter. I should've gone the shorter route, but I end up liking to play with mapcar and lambda too much LOL Oh wait. I see a slight problem with yours! The OP wants an "AND" conditional test for "ANCHOR", "RNOTES", and any "DTBLK*". Yours will return any one of those when it needs for return T only if all three conditions are true. Edited August 20 by pkenewell Quote
Tsuky Posted August 20 Posted August 20 6 hours ago, pkenewell said: @Tsuky Oh wait. I see a slight problem with yours! The OP wants an "AND" conditional test for "ANCHOR", "RNOTES", and any "DTBLK*". Yours will return any one of those when it needs for return T only if all three conditions are true. Your are right, I think that an '(OR it's a good boleeann opération to include in the test. for can be T is returned. Thank, I let to anyone to add this condition. 1 Quote
pkenewell Posted August 21 Posted August 21 (edited) @C. Roberts FWIW, here is a version that is may not the shortest code, but makes it more understandable I think. Also using some Visual LISP functions as an alternate to my original code: ;; Function to search the Block Library using a wildcard match. ;; returns a list of the block names matching [pat]. (defun pjk-BlockFind (pat / bl) ;; Alternate using old AutoLISP method ;; (setq bl (list (cdr (assoc 2 (tblnext "BLOCK" T))))) ;; add all the other block names. ;; (while (setq b (tblnext "BLOCK")) ;; (setq bl (cons (cdr (assoc 2 b)) bl)) ;; ) ;; Version using Visual LISP Objects (vl-load-com) (vlax-for x (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object) ) ) (setq bl (cons (vla-get-name x) bl)) ) ;; filter the block list by using wcmatch (vl-remove-if '(lambda (y)(= y nil)) (mapcar '(lambda (x)(if (wcmatch x pat) x nil)) bl) ) ); end defun ; conditional test for block names "ANCHOR", "RNOTES", and search for and "DTBLK" with 1 or 2 Alpha chracters on the end. ; note - it could just be "DTBLK*" in the wcmatch if it doesn't matter what the suffix is. (cond ( (and (tblsearch "BLOCK" "ANCHOR") (tblsearch "BLOCK" "RNOTES") (> (length (pjk-BlockFind "DTBLK@, DTBLK@@")) 0) ) (princ "\nAll qualified blocks were found. ") ) ) Edited August 21 by pkenewell Quote
ronjonp Posted August 21 Posted August 21 @pkenewell FWIW you could do your filtering while grabbing the name rather than using vl-remove-if on the whole list at the end. (defun pjk-blockfind (pat / bl) (vlax-for x (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (and (wcmatch (vla-get-name x) pat) (setq bl (cons (vla-get-name x) bl))) ) bl ) 1 Quote
pkenewell Posted August 22 Posted August 22 (edited) @ronjonp Not exactly. The wcmatch itself, is implicitly an OR match. The OP wanted all three conditions to be true; i.e. the blocks "ANCHOR" AND "RNOTES", AND any one of the matching (implicit OR) "DTBLK@, DTBLK@@". if you just did a wcmatch like "ANCHOR, RNOTES, DTBLK@, DTBLK@@" then is would return true for any ONE of those matches. EDIT: nevermind - you were just talking about changing my sub-function [edit] *TO BE SHORTER*. [edit2: removed other crap] Edited August 22 by pkenewell Quote
ronjonp Posted August 22 Posted August 22 7 minutes ago, pkenewell said: @ronjonp Not exactly. The wcmatch itself, is implicitly an OR match. The OP wanted all three conditions to be true; i.e. the blocks "ANCHOR" AND "RNOTES", AND any one of the matching (implicit OR) "DTBLK@, DTBLK@@". if you just did a wcmatch like "ANCHOR, RNOTES, DTBLK@, DTBLK@@" then is would return true for any ONE of those matches. I don't understand? Your function and my modification return the same thing? The valid pattern is set outside of the function? (and (tblsearch "BLOCK" "ANCHOR") (tblsearch "BLOCK" "RNOTES") (> (length (pjk-blockfind "DTBLK@, DTBLK@@")) 0) ) FWIW (setq bl '("A" "B" "C") pat "A,C" ) ;; This (vl-remove-if '(lambda (y) (= y nil)) (mapcar '(lambda (x) (if (wcmatch x pat) x nil ) ) bl ) ) ;; ("A" "C") ;; Is the same as this? (vl-remove-if-not '(lambda (x) (wcmatch x pat)) bl) ;; ("A" "C") 1 Quote
pkenewell Posted August 22 Posted August 22 (edited) 20 minutes ago, ronjonp said: I don't understand? Your function and my modification return the same thing? The valid pattern is set outside of the function? Yes You're right. You caught me in the middle of editing my previous response (see above LOL). I responded too fast and realized you were just suggesting to shorten my sub-function to return T or nil [Edit WRONG my bad - still returns list]. Cheers Edited August 22 by pkenewell Quote
pkenewell Posted August 22 Posted August 22 3 minutes ago, ronjonp said: FWIW Also good (vl-remove-if-not) is shorter. I get confused on those functions. Quote
pkenewell Posted August 22 Posted August 22 @ronjonp Darn - I was incorrect again. I see your version of my sub-function also returns the list of blocks. I guess I'm out of it this morning! your original edit is exactly the same except shorter. My apologies! Quote
pkenewell Posted August 22 Posted August 22 (edited) @C. RobertsOK - Updated version with @ronjonp's edit: ;; Function to search the Block Library using a wildcard match. ;; returns a list of the block names matching [pat]. ;; 8/22/2024 Thanks RONJONP for the edit to make it shorter (defun pjk-blockfind (pat / bl) (vl-load-com) (vlax-for x (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object))) (and (wcmatch (vla-get-name x) pat) (setq bl (cons (vla-get-name x) bl))) ) bl ) ; conditional test for block names "ANCHOR", "RNOTES", and search for and "DTBLK" with 1 or 2 Alpha chracters on the end. ; note - it could just be "DTBLK*" in the match pattern if it doesn't matter what the suffix is. (cond ( (and (tblsearch "BLOCK" "ANCHOR") (tblsearch "BLOCK" "RNOTES") (> (length (pjk-BlockFind "DTBLK@, DTBLK@@")) 0) ) (princ "\nAll qualified blocks were found. ") ) ) Edited August 22 by pkenewell 1 Quote
ronjonp Posted August 22 Posted August 22 24 minutes ago, pkenewell said: @ronjonp Darn - I was incorrect again. I see your version of my sub-function also returns the list of blocks. I guess I'm out of it this morning! your original edit is exactly the same except shorter. My apologies! No worries! Just trying to help out 1 Quote
C. Roberts Posted August 26 Author Posted August 26 Thank you @pkenewell and @ronjonp for the help. Very much a beginner here trying to learn. With your help I was able to cut out about 200 lines of code. 1 Quote
BIGAL Posted August 26 Posted August 26 When you get to like 1200 lines of code start looking for code improvements using defuns for repeating patterns of code. You can also make library lisp code and load it as part of your code. An example 100 lines of code, Multi radio buttons.lsp making a radio button DCL, but in your code is only 3 lines. Using Foreach can be used in a loop to say set variables( ("osmode" 0)("Grid" 1)....) a couple of lines v's a line for each setvar. A more advanced task sometimes you don't know how many variables you need eg X1, X2... you can make multiple variables and assign a value. Anyway just ask for help when your stuck good to see your having a go at coding. 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.