TheSwamp

Code Red => AutoLISP (Vanilla / Visual) => Topic started by: Rabbit on January 02, 2013, 02:04:40 PM

Title: Alternate for getkword
Post by: Rabbit on January 02, 2013, 02:04:40 PM
Here's my situation;  I got a lot of code that will get the visibility parameters from a block and bring that up in the quick properties panel on the screen.  The user picks the visibility they want and the code sets that.  The code does more than just that, but that's just the jist of it.

My problem is using initget before the getkword.  The code gets the visibility parameters and processes it into a string with all of the visilibity parameters separated by spaces for the initget to use.  Since all of the blocks have visibility parameters that have an underscore in them, initget goes screwy.

I thought, "Hey, why not write code to replace the underscores with hyphens and then convert it back."  Nope.  That won't work because some of the visibility parameters have both underscores and hyphens.

So, does anybody have a work around for this?

Sample code:
Code - Auto/Visual Lisp: [Select]
  1.  
  2. (initget "Abc Def X_y X_y-z")
  3.   (setq ParameterType (getkword "\nType ["Abc/Def/X_y/X_y-z"]"))
  4.  

If it's hard to understand, just let me know and I'll try to explain better.

Rabbit
Title: Re: Alternate for getkword
Post by: CAB on January 02, 2013, 02:35:04 PM
I thought, "Hey, why not write code to replace the underscores with hyphens and then convert it back."  Nope.  That won't work because some of the visibility parameters have both underscores and hyphens.

You can use a reference list.

Code: [Select]
(setq MyKeyWords (list "Abc" "Def" "X_y" "X_y-z"))
(setq ModList (RemoveUnderScore MyKeyWords)) ; returns ("Abc" "Def" "X-y" "X-y-z")
(initget (ADDSpaces ModList))
 (setq Answer (getkword (strcat "\nType ["(ADDSpaces ModList)"]")))
(setq  ParameterType (nth (vl-position Answer ModList) MyKeyWords))

Hope you get the gist.

Title: Re: Alternate for getkword
Post by: Rabbit on January 02, 2013, 02:48:29 PM
OH WOW!  :-o  That's brilliant.  I would've never come up with something like that.

Simple and easy to use.  Thanks CAB!

Rabbit
(note to self:  Always proofread a post before posting.  The grammar police might be watching :police: )   :lmao:
Title: Re: Alternate for getkword
Post by: Lee Mac on January 02, 2013, 02:50:57 PM
Or perhaps:

Code - Auto/Visual Lisp: [Select]
  1. (setq lst (mapcar 'strcase '("Abc" "Def" "X_y" "X_y-z")))
  2.     (not
  3.         (or (= "" (setq str (strcase (getstring "\nType: "))))
  4.             (member str lst)
  5.         )
  6.     )
  7.     (princ "\nInvalid Type.")
  8. )
Title: Re: Alternate for getkword
Post by: irneb on January 03, 2013, 02:09:45 AM
Just a query CAB: Where are those functions RemoveUnderScore & AddSpaces. I generally just use vl-string-translate and then just a mapcar construct
Code - Auto/Visual Lisp: [Select]
  1. (defun PrepareList->StrCat  (lst sep old new /)
  2.                  (mapcar '(lambda (s) (strcat sep (strcase (vl-string-translate old new s)))) lst))
  3.           (1+ (strlen sep))))
  4.  
  5. (setq lst '("Abc" "Def" "X_y" "X_y-z"))
  6. (initget (PrepareList->StrCat lst " " " _" "--")
  7. (setq Answer (getkword (strcat "\nType [" (PrepareList->StrCat lst "/" " _" "--") "]: ")))
Title: Re: Alternate for getkword
Post by: CAB on January 03, 2013, 09:08:28 AM
I didn't include them.  Some fishing :-)
Title: Re: Alternate for getkword
Post by: Rabbit on January 04, 2013, 09:56:43 AM
irneb,  here's what I wrote for the underscore replacer.  Probably not as elegant as what CAB and LEE can do, but it works.

Code - Auto/Visual Lisp: [Select]
  1. ;;;the variable lst is a list of strings, i.e. (list "Abc" "Def" "X_y" "X_y-z")
  2. (defun RemoveUnderScore (lst / cnt item rlst)
  3.   (setq cnt (1- (length lst)))
  4.   (while (>= cnt 0)
  5.     (setq item (nth cnt lst))
  6.     (while (vl-string-search "_" item)
  7.       (setq item (strcat (substr item 1 (vl-string-search "_" item)) "-" (substr item (+ (vl-string-search "_" item) 2))))
  8.     );while
  9.     (setq rlst (cons item rlst))
  10.     (setq cnt (1- cnt))
  11.   );while
  12.   rlst
  13. );defun
  14.  

The way I wrote my code I didn't need to use the AddSpaces sub-routine.

Rabbit
Title: Re: Alternate for getkword
Post by: Lee Mac on January 04, 2013, 10:26:22 AM
Consider vl-string-translate as Irneb has noted:

Code - Auto/Visual Lisp: [Select]
  1. _$ (mapcar '(lambda ( x ) (vl-string-translate "_" "-" x)) '("Abc" "Def" "X_y" "X_y-z"))
  2. ("Abc" "Def" "X-y" "X-y-z")
Title: Re: Alternate for getkword
Post by: Rabbit on January 04, 2013, 01:23:36 PM
See!  I knew there was a better and more elegant way of doing it.  Hopefully the whole lambda/mapcar thing will sink into my brain and I can truly understand the usage.  No matter what all I read about it, it still keeps me confused. :wink:
Title: Re: Alternate for getkword
Post by: irneb on January 07, 2013, 12:45:32 AM
Lambda is actually quite simple. It's not much different from making a normal defun and then calling it - it's just that the declaration (i.e. defining the defun) and the invocation (i.e. calling it) is in the same place and that there's no name declared for the function. E.g. the following 2 portions do much the same thing:
Code - Auto/Visual Lisp: [Select]
  1. ;; The normal defun way
  2. (defun add-mult (x y) (* (+ x y) y)) ;Creates a function called add-mult
  3. (add-mult 10 5) ;Invokes the add-mult function with arguments, returns the value 75
  4.  
  5. ;; Using lambda instead
  6. ((lambda (x y) (* (+ x y) y)) ;Defines an unnamed / temporary function
  7.   10 5) ;Send the arguments to the unnamed function and return 75

Now mapcar is a form of loop. It's meant to loop through one or more lists, calculating something for each item (or set of items) and returning a list with the new values for each iteration. The first argument to mapcar is the function (quoted so it can be applied with an arbitrary number of arguments) to invoke on each set of items, the next arguments are the source list(s). E.g. say you had the add-mult defun already. Then you can send 2 lists of numbers to it through mapcar:
Code - Auto/Visual Lisp: [Select]
  1. (defun add-mult (x y) (* (+ x y) y)) ;Declare the function first
  2.  
  3. (mapcar 'add-mult '(2 3 4 5) '(7 6 5 4 3 2)) ;Returns a new list: (63 54 45 36)
Note the source lists need not be the same length, but the returned list is the same length as the shortest source.

Usually you'd use lambda inside the mapcar instead of making a new defun just so you can send it to mapcar as above. So instead of making the function first and then sending it into mapcar, use lambda so it's done in one step and does not use up some symbol name:
Code - Auto/Visual Lisp: [Select]
  1. (mapcar '(lambda (x y) (* (+ x y) y)) '(2 3 4 5) '(7 6 5 4 3 2)) ;Also returns (63 54 45 36)
Title: Re: Alternate for getkword
Post by: CAB on January 07, 2013, 07:20:58 AM
It does take some practice but you will learn if you do some for your self.

----------  Mapcar  Lambda  Apply   ------------
http://www.theswamp.org/index.php?topic=2953.0   (MP)
http://www.theswamp.org/index.php?topic=340.0   (CAB)
http://www.cadtutor.net/forum/showthread.php?52127-Mapcar-lambda-Description
http://lee-mac.com/mapcarlambda.html
Title: Re: Alternate for getkword
Post by: Rabbit on January 08, 2013, 10:35:26 AM
Nice explanations guys.  I think I understand it now.  I may have to go back and update my routines.  By using mapcar and lambda the code will be a lot smaller.

Rabbit
Title: Re: Alternate for getkword
Post by: irneb on January 08, 2013, 02:26:03 PM
By using mapcar and lambda the code will be a lot smaller.
That's usually the major reason for using them. Smaller code means less possibility for errors thus makes it easier to get something working properly.
Title: Re: Alternate for getkword
Post by: Lee Mac on January 08, 2013, 05:49:23 PM
By using mapcar and lambda the code will be a lot smaller.
That's usually the major reason for using them. Smaller code means less possibility for errors thus makes it easier to get something working properly.

Not to mention concision *usually* results in greater efficiency...
Title: Re: Alternate for getkword
Post by: irneb on January 09, 2013, 01:22:02 AM
Not to mention concision *usually* results in greater efficiency...
Well it's definitely more efficient to write the code! Less to type :)
Title: Re: Alternate for getkword
Post by: Rabbit on January 09, 2013, 04:50:18 PM
Since this thread was originally about KWORDs, I got to thinking, there's got to be a better way.

A long time ago I got a hold of this little routine:
(Works best if Dynamic Input is turned on, then it's just a click and go thing)

Code - Auto/Visual Lisp: [Select]
  1. ;;;------------------------------------------------------------------------------------------------
  2. ;;;Tony Tanzillo - Gets the default return string for user input
  3. (defun xgetstring (msg StringInput / s)
  4.    (setq s
  5.       (getstring
  6.          (strcat "\n" msg
  7.             (cond (StringInput (strcat " <" StringInput ">: "))
  8.                   (t ": ")))))
  9.    (cond ((eq s "") StringInput) (t s))
  10. )
  11.  

And I made some modifications and came up with this:

Code - Auto/Visual Lisp: [Select]
  1. ;;;------------------------------------------------------------------------------------------------
  2. ;;;Written by Jamie Myers
  3. ;;;Loose extrapilation from Tony Tanzillo's XGETSTRING sub-routine
  4. (defun xgetkword (msg StringInput / s)
  5.    (setq s
  6.           (getkword
  7.             (strcat "\n" msg
  8.                     (cond (StringInput (strcat " <" StringInput ">: "))
  9.                           (t ": ")))))
  10.    (cond ((eq s nil) StringInput) (t s))
  11. )
  12.  

It requires a default variable bet set and an initget call before the routine is run.
Code - Auto/Visual Lisp: [Select]
  1. (setq rpt "Yes")
  2. (initget "Yes No")
  3. (setq rpt (xgetkword "\nContinue? [Yes/No]" rpt))
  4.  

And that has worked well for me for a long time.  But, then again, I'm somewhat lazy.  I wanted to create a better getkword function.  So I came up with this:

Code - Auto/Visual Lisp: [Select]
  1. ;;;------------------------------------------------------------------------------------------------
  2. ;;;Written by Jamie Myers 01-09-2013
  3. ;;;Inspiration fromTony Tanzillo's XGETSTRING sub-routine,
  4. ;;;and help from irneb, CAB and Lee Mac
  5. ;;;Use:      (setq <Variable> (GetKwordSub <message> <list of strings> <Variable>))
  6. ;;;Example:  (setq ReturnString (GetKwordSub "Selection" (list "Yes" "No" "Maybe" "A bc" "A-bc" "X_Y-z") ReturnString))
  7.  
  8. (defun GetKwordSub (Msg StringList Default / Msg Default Answer StringList ModList Cnt Setinitget Setmessage)
  9.   (if (not Default) (setq Answer (nth 0 StringList)) (setq Answer Default));set default if there is none
  10.   (setq ModList (mapcar '(lambda ( x ) (vl-string-translate " " "-" (vl-string-translate "_" "-" x))) StringList));Use hyphens instead of underscores and spaces
  11.   (setq Cnt (1- (length ModList)))
  12.   (while (> Cnt -1);iterate through the list to create 2 strings, one for the initget call and one for the message
  13.     (setq Temp (nth Cnt ModList))
  14.     (if (not Setinitget)
  15.       (setq Setinitget Temp)
  16.       (setq Setinitget (strcat Temp " " Setinitget)))
  17.     (if (not Setmessage)
  18.       (setq Setmessage Temp)
  19.       (setq Setmessage (strcat Temp "/" Setmessage)))
  20.     (setq Cnt (1- Cnt))
  21.   );while
  22.   (initget Setinitget)
  23.   (setq Answer
  24.          (getkword
  25.             (strcat "\n" Msg "[" Setmessage "]"
  26.                     (cond (Answer (strcat " <" Answer ">: "))
  27.                           (t ": ")))))
  28.   (cond ((eq Answer nil) Answer) (t Answer))
  29.   (nth (vl-position Answer ModList) StringList)
  30. );defun
  31.  
  32.  

It has issues.  Using the example call, it gets confused between "A bc" and "A-bc".  My thinking is that there more than likely will never be an issue.
I've added a few comments to get and idea of what's going on.
Anyways, what do the experts say.  And of course, I want to see if it will even work for someone else.

Rabbit
Title: Re: Alternate for getkword
Post by: irneb on January 09, 2013, 11:51:13 PM
Try this one:
Code - Auto/Visual Lisp: [Select]
  1. (defun getkword+  (msg options default / Lst->Opt values)
  2.   (defun Lst->Opt  (lst sep old new /)
  3.     (substr
  4.       (apply 'strcat
  5.              (mapcar
  6.                '(lambda (s) (strcat sep s))
  7.                (setq values (mapcar '(lambda (s) (strcase (vl-string-translate old new s))) lst))))
  8.       (1+ (strlen sep))))
  9.   (initget (Lst->Opt options " " " _" "--"))
  10.   (if (setq msg (vl-position
  11.                   (cond (default
  12.                          (cond ((getkword (strcat msg
  13.                                                   " ["
  14.                                                   (Lst->Opt options "/" " _" "--")
  15.                                                   "] <"
  16.                                                   (setq default (strcase default))
  17.                                                   ">: ")))
  18.                                (default)))
  19.                         (t (getkword (strcat msg " [" (Lst->Opt options "/" " _" "--") "]: "))))
  20.                   values))
  21.     (nth msg options)))

You use it thus:
Code: [Select]
Command: (getkword+ "Testing" '("Yes" "No") nil)
Testing [YES/NO]:
nil
Command: (getkword+ "Testing" '("Yes" "No") nil)
Testing [YES/NO]: y
"Yes"
Command: (getkword+ "Testing" '("Yes" "No") nil)
Testing [YES/NO]: n
"No"
Command: (getkword+ "Testing" '("Yes" "No") "Yes")
Testing [YES/NO] <YES>:
"Yes"
Command: (getkword+ "Testing" '("Yes" "No") "Yes")
Testing [YES/NO] <YES>:
"Yes"
Command: (getkword+ "Testing" '("Yes" "No") "Yes")
Testing [YES/NO] <YES>: n
"No"
It works with the pick a keyword also. It would allow for spaces in the keywords as well.
Title: Re: Alternate for getkword
Post by: Rabbit on January 10, 2013, 11:55:02 AM
Wow.  I mean WOW!  I expected suggestions like "Change this part to this", or, "Change this other stuff to that", but what you came up with is a totally new thing.  Very impressive.  My eyes have been opened to a whole new way of looking at some situations.

Thank you for sharing your knowledge.

Rabbit
Title: Re: Alternate for getkword
Post by: CAB on January 10, 2013, 12:43:12 PM
This is an old post but may give some ideas for keyword routines.
http://www.theswamp.org/index.php?topic=6992.msg93574#msg93574
Title: Re: Alternate for getkword
Post by: irneb on January 10, 2013, 11:51:36 PM
Thank you for sharing your knowledge.
Pleasure! Glad I could help someone. Though my code is not much more than an amalgamation of all the ideas in this thread.