From AutoCAD
;;;WIKI-STRTOLST
;;;Parses a string into a list of fields.
;;;Usage: (wiki-strtolst
;;; [InputString containing fields]
;;; [FieldSeparatorWC field delimiter wildcard string
;;; Use "`," for comma and " ,\t" for white space
;;; ]
;;; [TextDelimiter text delimiter character.]
;;; [EmptyFieldsDoCount flag.
;;; If nil, consecutive field delimiters are ignored.
;;; Nil is good for word (white space) delimited strings.
;;; ]
;;; )
;;; Examples:
;;; CSV (wiki-strtolst string "`," "\"" T)
;;; Word delimited (wiki-strtolst string " ,\t,\n" "" nil)
;;; Revision history
;;; 2009-01-17 TGH Replaced test for empty fieldseparatorwc with a simple '= function
;|
Edit the source code for this function at
http://autocad.wikia.com/wiki/Strtolst_(AutoLISP_function)
|;
;;;Avoid cleverness.
;;;Human readability trumps elegance and economy and cleverness here.
;;;This should be readable to a programmer familiar with any language.
;;;In this function, I'm trying to honor readability in a new (2008) way.
;;;And I am trying a new commenting style.
;;;Tests
;;;(alert (apply 'strcat (mapcar '(lambda (x) (strcat "\n----\n" x)) (wiki-strtolst "1 John,\"2 2\"\" pipe,\nheated\",3 the end,,,,," "`," "\"" nil))))
;;;(alert (apply 'strcat (mapcar '(lambda (x) (strcat "\n----\n" x)) (wiki-strtolst "1 John,\"2 2\"\" pipe,\nheated\",3 the end,,,,," "`," "\"" T))))
(DEFUN
WIKI-STRTOLST (INPUTSTRING FIELDSEPARATORWC TEXTDELIMITER
EMPTYFIELDSDOCOUNT / CHARACTERCOUNTER CONVERSIONISDONE
CURRENTCHARACTER CURRENTFIELD CURRENTFIELDISDONE
FIRSTCHARACTERINDEX PREVIOUSCHARACTER RETURNLIST
TEXTMODEISON
)
;;Initialize the variables for clarity's sake
(SETQ
;;For the AutoLISP (substr string index length) function, the first character index is 1
FIRSTCHARACTERINDEX 1
;;We start the character counter one before the beginning
CHARACTERCOUNTER
(1- FIRSTCHARACTERINDEX)
PREVIOUSCHARACTER ""
CURRENTCHARACTER ""
CURRENTFIELD ""
CURRENTFIELDISDONE NIL
TEXTMODEISON NIL
CONVERSIONISDONE NIL
RETURNLIST NIL
)
;;Make sure that the FieldSeparatorWC is not empty.
(COND
;;If the FieldSeparatorWC is an empty string,
((= FIELDSEPARATORWC "")
;;Then
;;1. Give an alert about the problem.
(ALERT
;;Include princ to allow user to see and copy error
;;after dismissing alert box.
(PRINC
(STRCAT
"\n\""
FIELDSEPARATORWC
"\" is not a valid field delimiter."
)
)
)
;;2. Exit with error.
(EXIT)
)
)
;;Start the main character-by-character InputString examination loop.
(WHILE (NOT CONVERSIONISDONE)
(SETQ
;;Save CurrentCharacter as PreviousCharacter.
PREVIOUSCHARACTER
CURRENTCHARACTER
;;CharacterCounter is initialized above to start 1 before first character. Increment it.
CHARACTERCOUNTER
(1+ CHARACTERCOUNTER)
;;Get new CurrentCharacter from InputString.
CURRENTCHARACTER
(SUBSTR INPUTSTRING CHARACTERCOUNTER 1)
)
;;Decide what to do with CurrentCharacter.
(COND
;;If
((AND
;;there is a TextDelimiter,
(/= TEXTDELIMITER "")
;;and CurrentCharacter is a TextDelimiter,
(= CURRENTCHARACTER TEXTDELIMITER)
)
;;then
;;1. Toggle the TextModeIsOn flag
(IF (NOT TEXTMODEISON)
(SETQ TEXTMODEISON T)
(SETQ TEXTMODEISON NIL)
)
;;2. If this is the second consecutive TextDelimiter character, then
(IF (= PREVIOUSCHARACTER TEXTDELIMITER)
;;Output it to CurrentField.
(SETQ CURRENTFIELD (STRCAT CURRENTFIELD CURRENTCHARACTER))
)
)
;;Else if CurrentCharacter is a FieldDelimiter wildcard match,
((WCMATCH CURRENTCHARACTER FIELDSEPARATORWC)
;;Then
(COND
;;If TextModeIsOn = True, then
((= TEXTMODEISON T)
;;Output CurrentCharacter to CurrentField.
(SETQ CURRENTFIELD (STRCAT CURRENTFIELD CURRENTCHARACTER))
)
;;Else if
((OR ;;EmptyFieldsDoCount, or
(= EMPTYFIELDSDOCOUNT T)
;;the CurrentField isn't empty,
(/= "" CURRENTFIELD)
)
;;Then
;;Set the CurrentFieldIsDone flag to true.
(SETQ CURRENTFIELDISDONE T)
)
(T
;;Else do nothing
;;Do not flag the CurrentFieldDone,
;;nor output the CurrentCharacter.
NIL
)
)
)
;;Else if CurrentCharacter is empty,
((= CURRENTCHARACTER "")
;;Then
;;We are at the end of the string.
;;1. Flag ConversionIsDone.
(SETQ CONVERSIONISDONE T)
;;2. If
(IF (OR ;;EmptyFieldsDoCount, or
EMPTYFIELDSDOCOUNT
;;the PreviousCharacter wasn't a FieldSeparatorWC, or
(NOT (WCMATCH PREVIOUSCHARACTER FIELDSEPARATORWC))
;;the ReturnList is still nil due to only empty non-counting fields in string,
;;(Added 2008-02-18 TGH. Bug fix.)
(= RETURNLIST NIL)
)
;;Then flag the CurrentFieldIsDone to wrap up the last field.
(SETQ CURRENTFIELDISDONE T)
)
)
;;Else (CurrentCharacter is something else),
(T
;;Output CurrentCharacter to CurrentField.
(SETQ CURRENTFIELD (STRCAT CURRENTFIELD CURRENTCHARACTER))
)
)
;;If CurrentFieldIsDone,
(IF CURRENTFIELDISDONE
;;Then
;;Output it to the front of ReturnList.
(SETQ
RETURNLIST
(CONS CURRENTFIELD RETURNLIST)
;;Start a new CurrentField.
CURRENTFIELD
""
CURRENTFIELDISDONE NIL
)
)
;;End the main character-by-character InputString examination loop.
)
;;Reverse the backwards return list and we are done.
(REVERSE RETURNLIST)
)