Update - Sample code was revised to include some additional error handling and return some basic error messages in the case of nil being passed to the function.
When working with file paths in AutoCAD, it is common that you might need to work with a string that contains multiple paths that are separated by a delimiter. Commonly, the delimiter used to separate one path from another is a semi-colon (;).
The ACADPREFIX system variable returns a string that contains a listing of all the AutoCAD support paths.
(getvar "acadprefix")
"C:\Users\ambrosl\appdata\roaming\autodesk\autocad 2017\r21.0\enu\support;C:\program files\autodesk\autocad 2017\support;C:\program files\autodesk\autocad 2017\support\en-us;C:\program files\autodesk\autocad 2017\fonts;C:\program files\autodesk\autocad 2017\help;C:\program files\autodesk\autocad 2017\express;C:\program files\autodesk\autocad 2017\support\color;C:\Program Files\Autodesk\AutoCAD 2017\drv;"
The following code defines a function named SPLIT which breaks up a string into elements with in a list based on the delimiter specified:
;; Usage: (split (getvar "acadprefix") ";")
(defun split (sExpression sDelimiter / len val sList)
(if (and (= (type sExpression) 'STR) (= (type sDelimiter) 'STR))
(progn
; Get the length of the first item from the expression based
; on delimiter position
(setq len (vl-string-position (ascii sDelimiter) sExpression))
; Loop until there are no more instances of the delimiter
; in the expression
(while (numberp len)
; Get the item from the expression
(setq val (substr sExpression 1 len))
; Append the item to the list
(setq sList (cons val sList))
; Get the remaining part of the expression
(setq sExpression (substr sExpression (+ 2 len)))
; Get the length of the next item from the string based
; on delimiter position
(setq len (vl-string-position (ascii sDelimiter) sExpression))
)
; Add the last value to the list
(if (/= sExpression nil)
(setq sList (cons sExpression sList))
)
; Reverses the elements in the list and return the list
(reverse sList)
)
(progn
(if (not (= (type sExpression) 'STR))
(prompt "\nSplit Error: First argument must be the string to split.")
)
(if (not (= (type sDelimiter) 'STR))
(prompt "\nSplit Error: Second argument must be the character that represents the delimiter to use.")
)
(princ)
)
)
)
The results of using the SPLIT function on the ACADPREFIX system variable is as follows:
(split (getvar "acadprefix") ";")
("C:\\Users\\ambrosl\\appdata\\roaming\\autodesk\\autocad 2017\\r21.0\\enu\\support" "C:\\program files\\autodesk\\autocad 2017\\support" "C:\\program files\\autodesk\\autocad 2017\\support\\en-us" "C:\\program files\\autodesk\\autocad 2017\\fonts" "C:\\program files\\autodesk\\autocad 2017\\help" "C:\\program files\\autodesk\\autocad 2017\\express" "C:\\program files\\autodesk\\autocad 2017\\support\\color" "C:\\Program Files\\Autodesk\\AutoCAD 2017\\drv" "")
The SPLIT function can also be used to separate the name of an Xref from a named style or layer name.
For example, Grid Plan|Architectural_Plan_Dim is the layer name created in a host drawing after the drawing file named Grid Plan is attached and that drawing that contains a layer named Architectural_Plan_Dim. The pipe (|) character is used to separate the Xref name from the layer name.
(split "Grid Plan|Architectural_Plan_Dim" "|")
("Grid Plan" "Architectural_Plan_Dim")
Sincerely,
Lee
Only a small correction:
(Getenv "ACADPrefix") ";") is erroneous.
Use: (getvar "acadprefix") or (getenv "ACAD")
regards
Posted by: José Luis García Galán | Tuesday, February 07, 2017 at 04:45 AM
Thanks for catching the issue, the sample has been fixed. The original content I had wrote used an environment variable.
Posted by: Lee Ambrosius | Tuesday, February 07, 2017 at 07:35 AM
I think you'll find this old 'parser' routine offers a substantial boost in efficiency:
https://www.theswamp.org/index.php?topic=42354.msg475130#msg475130
[code]
(defun _Parser (char string / i segments segment)
(while (setq i (vl-string-search char string))
(setq segments (cons (setq segment (substr string 1 i)) segments))
(setq string (substr string (+ 2 i)))
)
(reverse (cons string segments))
)
[/code]
Here's a quick speed test:
[code]
(setq s (getvar "acadprefix"))
(setq d ";")
(bench '(split) (list s d) 10000)
(bench '(_Parser) '(d s) 10000)
[/code]
... And the results from console:
[code]
_$
SPLIT
Elapsed: 2922
Average: 0.2922
_PARSER
Elapsed: 32
Average: 0.0032
[/code]
Now, how often will someone parse a string anywhere near this many times - admittedly seldom - just offering simplicity, and efficiency where I can, based on what I've learned.
Please do with this what you like.
Cheers
Posted by: BlackBox | Tuesday, February 07, 2017 at 09:19 AM
Thanks for sharing! There is always different ways to approach the same solution and performance is key when working with large data sets.
Posted by: Lee Ambrosius | Tuesday, February 07, 2017 at 10:17 AM