Jump to content

Use of wildcard or another function to shorten a section of code


C. Roberts

Recommended Posts

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!!

Link to comment
Share on other sites

@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 by pkenewell
Link to comment
Share on other sites

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)
))

 

  • Like 1
Link to comment
Share on other sites

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 by pkenewell
Link to comment
Share on other sites

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. 😜

  • Agree 1
Link to comment
Share on other sites

@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 by pkenewell
Link to comment
Share on other sites

@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
)

 

  • Like 1
Link to comment
Share on other sites

@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 by pkenewell
Link to comment
Share on other sites

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") 

 

  • Like 1
Link to comment
Share on other sites

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 by pkenewell
Link to comment
Share on other sites

3 minutes ago, ronjonp said:

FWIW

Also good (vl-remove-if-not) is shorter. I get confused on those functions.

Link to comment
Share on other sites

@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!

Link to comment
Share on other sites

@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 by pkenewell
  • Thanks 1
Link to comment
Share on other sites

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  :beer:

  • Like 1
Link to comment
Share on other sites

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.

  • Like 1
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...