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