Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Any way to assign a lisp variable both its name and its value from a string?

41 REPLIES 41
Reply
Message 1 of 42
Anonymous
2390 Views, 41 Replies

Any way to assign a lisp variable both its name and its value from a string?

 

I.e. given a string "varname1:varval1,varname2:varval2" end up with the equivalent of calling this: (setq varname1 varval1 varname2 varval2) in a lisp routine

 

(I'm flexible as to exact structure of the string, characters used as connectors or spacers, etc.)

41 REPLIES 41
Message 2 of 42
Ajilal.Vijayan
in reply to: Anonymous

Start with something like this

 

Instead of string this code is using List.

 

(defun c:test ()
(setq var_list '(varname1 varval1 varname2 varval2))
(setq a 0)
(setq b 1)
(repeat (/(length var_list)2)
(set (nth a var_list) (nth b var_list))
(setq a ( + a 2))
(setq b ( + b 2))
);repeat
)

 

Message 3 of 42
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

 

I.e. given a string "varname1:varval1,varname2:varval2" end up with the equivalent of calling this: (setq varname1 varval1 varname2 varval2) in a lisp routine

 

(I'm flexible as to exact structure of the string, characters used as connectors or spacers, etc.)


Another way to do it if the basis is a list such as in the first reply, and assuming the varnameX values are text strings:

 

(setq var_list '(varname1 varval1 varname2 varval2))

(while var_list ; still anything left?

  (set (read (car var_list)) (cadr var_list)); set first varval into first varname

  (setq var_list (cddr var_list)) ; take first varname and varval off

)

 

I guess it could be considered an advantage that in a list form rather than a continuous string, the varvalX entries don't need to be strings, but can be numbers, or other variable names, or lists, etc.

Kent Cooper, AIA
Message 4 of 42
dgorsman
in reply to: Anonymous

"Variable" variable names usually make things more complex than they need to be.  There's a number of other options which work very well, most of them being list oriented.  For example, a list of dotted pairs could be constructed as (("Variable name 1" . value ) ("Variable name 2" . value)).

 

Flexibility is good, but Jello makes for a lousy bridge.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 5 of 42
Gary_J_Orr
in reply to: Anonymous

short answer: yes, you could use "vl-string-search" and "substr" (watch the return values as one uses a zero based return value while the other uses a 1 based value so you will always be adding and subtracting...

 

But, if you're building the string programmatically you would be better off building a list of dotted pairs using "cons", then stepping through that list with a "foreach" stmt. This will create a list containing "dotted pairs":

 

(setq Varlist (cons (cons "varname1" "Varval1")  varlist))

 

repeat when you want to add another (wherever you are adding to your string)...

then use a foreach on the list with "car" and "cdr" to extract the values from each dotted pair within the list:

 

(foreach var Varlist (set (read (car var)) (cdr var)) )

 

Notice the call to "set" and "read" instead of "setq". in either your string version or my proposed list version you will need to "read" the value of the string into a variable name and "setq" can't do that.

Gary J. Orr
(Your Friendly Neighborhood) CADD/BIM/VDC Applications Manager
http://www.linkedin.com/in/garyorr

aka (current and past user names):
Gary_J_Orr (GOMO Stuff 2008-Present); OrrG (Forum Studio 2005-2008); Gary J. Orr (LHB Inc 2002-2005); Orr, Gary J. (Gossen Livingston 1997-2002)
Message 6 of 42
Kent1Cooper
in reply to: Anonymous

If the consolidated-string format is easier for you to construct, there are many routines on the Forums to split strings up around delimiting characters, and do various things with the results.  Just one example that makes a list of the subdivided pieces:

 

;;  by Stephan Koster, in "Converting a delimited string
;;  to a list" thread, ACAD Customization, 11/08/2001

(defun string2list (string delim / pos temp)
  (setq delim (ascii delim))
  (while (setq pos (vl-string-position delim string))
    (setq
      temp (cons (substr string 1 pos) temp)
      string (substr string (+ 2 pos))
    )
  )
  (reverse (cons string temp))
)

 

Using that, you could process your initial string:

 

(foreach pair (string2list YourString ","); divide overall into pairs around commas

  (setq name&val (string2list pair ":")); divide pair into name & value around colon

  (set (read (car name&val)) (cadr name&val))

)

Kent Cooper, AIA
Message 7 of 42
Anonymous
in reply to: Ajilal.Vijayan

I was thinking of a string because even I can think of a couple of ways to store one- inside or outside a drawing. Not so with a list, unless there's a way to construct a list from a string that equals the lisp code required to define the list and it's contents.

Message 8 of 42
Anonymous
in reply to: Kent1Cooper

I was thinking of storing the string as a block attribute. Selecting block ent data, accessing att values, etc all things I know how to do.

Message 9 of 42
Gary_J_Orr
in reply to: Anonymous

keep reading Nash,
Kent has also posted a solution by Stephan Koster that converts strings into lists to process. then included code to processes your example string and set the variables using the function that he posted.
looks robust enough to give you everything that you're looking for...
-G
Gary J. Orr
(Your Friendly Neighborhood) CADD/BIM/VDC Applications Manager
http://www.linkedin.com/in/garyorr

aka (current and past user names):
Gary_J_Orr (GOMO Stuff 2008-Present); OrrG (Forum Studio 2005-2008); Gary J. Orr (LHB Inc 2002-2005); Orr, Gary J. (Gossen Livingston 1997-2002)
Message 10 of 42
Anonymous
in reply to: Gary_J_Orr

Lisp is good at lists, I know. Assoc is an easy way to get at values too, but I was thinking of storing the string as a block attribute. I suppose I could construct the string to look like a list, but then still have have a way to convert the retrieved string to a list.

 

I've got a largish routine, twenty portrait tabloid pages, with loops, sometimes nested three deep, wherein variables are reassigned from prompts and functions performed. Right now each loop uses STRCAT to append lines to report strings, that the outer loop assembles into a larger report string that prints to screen and writes to a text file when all is done.

 

It is working fine on paper or screen, but it is a long series of prompts that have to be endured if you want to change one little thing along the way. If I could store the values from each loop, and then elect to accept a subset of the previous versions of the data I hope to permit more surgical revisions by being able to creating intermediate points of re-entry into the long chain of prompts which I now can only enter from the beginning. Because of the logic being applied, I'd still have to complete to the end the series of prompts from the re-entry point, but it would be an improvement.

 

Hope this makes sense. I have limited lisp skills: lambda and mapcar confound me. I try to use what I can understand, and when a routine works, I stop.

 

Message 11 of 42
Anonymous
in reply to: Kent1Cooper

Now I know how the cargo cultists felt.

 

I'm going to need more bamboo.

Message 12 of 42
Gary_J_Orr
in reply to: Anonymous

I believe that I understand what you are trying to do, IE: skip a bunch of your prompts during testing by having predefined the variables that they would set until you reach that point that you specifically want to test (where it will then start prompting you again)...

Here's your problem, and it has nothing to do with how you store and retrieve those variables at this point:
To do as you're hoping to do you will need to enclose every prompt for user input within an "if" stmt to see if that variable is already set... if it isn't set, then prompt for it, if it is set then skip the prompt...
By doing that then you could run a routine to predefine the variables from whatever source you want (again see the solution for a string conversion posted by Kent) but that will mean a lot of rewriting in your code to include "if" stmts for something that you will never use once you are done with the function(s)...
Of course, I've done the same thing myself from time to time so...
*ReallyBigGrin*
Gary J. Orr
(Your Friendly Neighborhood) CADD/BIM/VDC Applications Manager
http://www.linkedin.com/in/garyorr

aka (current and past user names):
Gary_J_Orr (GOMO Stuff 2008-Present); OrrG (Forum Studio 2005-2008); Gary J. Orr (LHB Inc 2002-2005); Orr, Gary J. (Gossen Livingston 1997-2002)
Message 13 of 42
Anonymous
in reply to: Gary_J_Orr

Almost got it, Gary. It's not just for the debugging exercise. It's for subsequent runs under normal use. It's an analytic program, so sometimes it uncovers a problem in a design that needs revision. After the revision you might want to run it again to make sure you actually fixed the design. You could also just mess up some data entry in the sequence without realizing and have to rerun.

 

Thanks to that bit of code by Stephan, in the worst case, I can now picture a way that I could offer at each prompt during the current run the value during the previous run of the program that you could accept one by one, wearing out one key on your keyboard.

 

The best case, which I can't exactly visualize as yet, would be that the string, or list, would itself support an interface to pick a re-entry point in the previous run, load all the values from the previous run up to that point, and then have the routine prompts carry on from that point. While it would be nice if the REST of the values from that point forward could be offered to the end of the current run, I'd have to include a fair number of tests to make sure that some of them are NOT offered because the possiblities in the sequence are often conditional on responses to previous prompts both for existence and potential value range. That might not be worth the overhead. I can see how DCL could preclude some of this, but my skills are even worse there.

 

As for the silly things we do in LISP, look around. Some people crush candy for hours.

Message 14 of 42
Gary_J_Orr
in reply to: Anonymous


@Anonymous wrote:

As for the silly things we do in LISP, look around. Some people crush candy for hours.


*LaughingOutLoud* Ain't that the truth... I'm back on the discussion boards looking for something to do out of sheer boredom due to a lack of work... this kinda stuff is much more interesting to me than those games, but I'm still doing the same thing Smiley Very Happy


@Anonymous wrote:
... It's not just for the debugging exercise. It's for subsequent runs under normal use.... After the revision you might want to run it again to make sure you actually fixed the design. You could also just mess up some data entry in the sequence without realizing and have to rerun....

Well then it's well worth the time to include to include the option.


@Anonymous wrote:

... I can now picture a way that I could offer at each prompt during the current run the value during the previous run of the program that you could accept one by one, wearing out one key on your keyboard.

 

The best case, which I can't exactly visualize as yet, would be that the string, or list, would itself support an interface to pick a re-entry point in the previous run, load all the values from the previous run up to that point, and then have the routine prompts carry on from that point...


It would seem that you are picturing something along the lines of issuing the "prompt" complete with a default to the previous variable. Tricky but definately do-able. But since you stated a preference to just use the previous variable without prompting you could try something like this:

drop the "helper functions" provided by Kent (with a little modification to bail out at your desired entry point and wrapped in a defun stmt) into your file:

;;  by Stephan Koster, in "Converting a delimited string
;;  to a list" thread, ACAD Customization, 11/08/2001
(defun string2list (string delim / pos temp)
  (setq delim (ascii delim))
  (while (setq pos (vl-string-position delim string))
    (setq
      temp (cons (substr string 1 pos) temp)
      string (substr string (+ 2 pos))
    )
  )
  (reverse (cons string temp))
)
 
 
;modified from Kent's suggestion to stop at the desired Entry Point
;using the name of a variable
(defun ReEntryAtX (varX YourString / TestFlag name&val)
  (setq TestFlag nil)
  (while (= nil TestFlag)
    (foreach pair (string2list YourString ","); divide overall into pairs around commas
      (setq name&val (string2list pair ":")); divide pair into name & value around colon
      (set (read (car name&val)) (cadr name&val))
      (if (= (strcase varX) (strcase (car name&val)))
	(setq TestFlag T)
	)
      )
    )
  )

 

At the start of your routine create an option:

      (initget 0 "Yes No")
      (setq SkipTo (getkword "\nSkip to Entry Point? \[Yes\/No\] <N>: "))
      (if (= "Yes" SkipTo)
        (progn
          (setq SkipTo (getstring "\nEnter entry point variable: "))
          ;insert code here to retrive your previously stored var string
          ;(setq VarStr ...)
          (ReEntryAtX SkipTo VarStr)
          )
        )

 

Then each of your "prompts" can be wrapped in an "if" stmt to see if that variable has already been set (which will give you the "silent skip to" that you would like:

(if (= nil WhateverVarName)

...whatever call(s) you make to set the var...

)

 

this, of course, depends on all users knowing the variable names... but, one step at a time...

G

 

 

Gary J. Orr
(Your Friendly Neighborhood) CADD/BIM/VDC Applications Manager
http://www.linkedin.com/in/garyorr

aka (current and past user names):
Gary_J_Orr (GOMO Stuff 2008-Present); OrrG (Forum Studio 2005-2008); Gary J. Orr (LHB Inc 2002-2005); Orr, Gary J. (Gossen Livingston 1997-2002)
Message 15 of 42
dbroad
in reply to: Anonymous

Nash,

If strings in attributes end up working for you, then you probably have enough information to proceed.  If they end up not working for you, then a couple of well documented options might be more suitable:  1) adding xrecord data to extension dictionaries attached to objects, 2) adding a dictionary to the drawing and adding the xrecord data to that dictionary, or 3)adding xdata, attached to objects.  Each of those methods is better than strings because they each support multiple data types, including handles.

 

If you like reactors (which can be tricky), you could also store some types of data on persistent object reactors. That would definitely be an in-house only choice due to the need to reload callback functions forever more.

Architect, Registered NC, VA, SC, & GA.
Message 16 of 42
Gary_J_Orr
in reply to: dbroad

dbroad,
I figured the ole boy had enough on his plate already without throwing Extension Dictionaries at him (which was my first thought for defining the var lists)... but... given that he had stated that he was already handling strings in his processing and that he could easily store/recover such I figured I'd leave off and just help address his stated question.
*ReallyBigGrin*
Gary J. Orr
(Your Friendly Neighborhood) CADD/BIM/VDC Applications Manager
http://www.linkedin.com/in/garyorr

aka (current and past user names):
Gary_J_Orr (GOMO Stuff 2008-Present); OrrG (Forum Studio 2005-2008); Gary J. Orr (LHB Inc 2002-2005); Orr, Gary J. (Gossen Livingston 1997-2002)
Message 17 of 42
Anonymous
in reply to: dbroad

Is there a Dictionaries for Dummies somewhere?

 

I was thinking I could handle the data types issue when stored in the string, e.g.

"SuiteNumber!MezzanineNumber@OccupancyAreaNumber#VarName$DataType^Value"

and then use the "DataType" as an argument in the variable restoration function.

Message 18 of 42
dbroad
in reply to: Gary_J_Orr

Hi Gary,

<grinback> Yes, but, since he is managing a 20 page lisp program to do iterative adaptive drawing analysis and modelling and since he knows such arcane facts as cargo_cult_programming, I thought he might be ready for more than his "Aw shucks maam" newbie personna might imply.</grinback>

Architect, Registered NC, VA, SC, & GA.
Message 19 of 42
dbroad
in reply to: Anonymous

In vlide, type vla-setxdata.  Then push the vlide help.  A complete lisp program for getting and setting xdata is provided. Although not exactly a dictionaries for dummies, it does provide a big step up.  Xdata might be more appropriate than generalized dictionaries since you have an application and since you need the data attached to the resulting objects.  AutoCAD 2014 help has made inroads to making the activeX help more pertinent for AutoLISP users.

 

The direct link is mk:@MSITStore:C:\Program%20Files\Common%20Files\Autodesk%20Shared\acadauto.chm::/IDH_SETXDATA.htm

 

Push Example hyperlink at top left.

Architect, Registered NC, VA, SC, & GA.
Message 20 of 42
Anonymous
in reply to: dbroad

Aw shucks : D My VLIDE doesn't format vla-setxdata like a valid function, the VLIDE help doesn't have any hits for it, and the link is a 404 on my box.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost