Jump to content

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


Recommended Posts

Posted

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

Posted (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 by pkenewell
Posted

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
Posted (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 by pkenewell
Posted
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
Posted (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 by pkenewell
Posted

@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
Posted (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 by pkenewell
Posted
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
Posted (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 by pkenewell
Posted
3 minutes ago, ronjonp said:

FWIW

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

Posted

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

Posted (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 by pkenewell
  • Thanks 1
Posted
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
Posted

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.

  • Like 1
Posted

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

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