Author Topic: Alternate for getkword  (Read 7971 times)

0 Members and 1 Guest are viewing this topic.

Rabbit

  • Guest
Alternate for getkword
« 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

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Alternate for getkword
« Reply #1 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.

I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Rabbit

  • Guest
Re: Alternate for getkword
« Reply #2 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:

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Alternate for getkword
« Reply #3 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. )

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Alternate for getkword
« Reply #4 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 "/" " _" "--") "]: ")))
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Alternate for getkword
« Reply #5 on: January 03, 2013, 09:08:28 AM »
I didn't include them.  Some fishing :-)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Rabbit

  • Guest
Re: Alternate for getkword
« Reply #6 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

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Alternate for getkword
« Reply #7 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")

Rabbit

  • Guest
Re: Alternate for getkword
« Reply #8 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:

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Alternate for getkword
« Reply #9 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)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Alternate for getkword
« Reply #10 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
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

Rabbit

  • Guest
Re: Alternate for getkword
« Reply #11 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

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Alternate for getkword
« Reply #12 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.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: Alternate for getkword
« Reply #13 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...

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Alternate for getkword
« Reply #14 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 :)
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Rabbit

  • Guest
Re: Alternate for getkword
« Reply #15 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

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Alternate for getkword
« Reply #16 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.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Rabbit

  • Guest
Re: Alternate for getkword
« Reply #17 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

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: Alternate for getkword
« Reply #18 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
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Alternate for getkword
« Reply #19 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.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.