From: Mark Kantrowitz
Subject: Re: How to read string with delimiter character?
Date: 
Message-ID: <C45DoA.3G3.1@cs.cmu.edu>
In article <·············@ro> ···@doe.carleton.ca (Dan D. He) writes:
>Would someone out there know how to read a string with delimiter? What
>I need is read a string like "abcd-efgh-ijk-lmn", I need to return
>"abcd". The "-" is the delimiter. 

This question comes up frequently. Essentially, you use POSITION to
find the position of the delimiter, and SUBSEQ to grab the appropriate
portion of the string.

The following code (from the extensions.lisp file in the Lisp
Utilities Repository) shows how to do this.

--mark

(defun parse-with-delimiter (line &optional (delim #\newline))
  "Breaks LINE into a list of strings, using DELIM as a 
   breaking point."
  ;; what about #\return instead of #\newline?
  (let ((pos (position delim line)))
    (cond (pos
           (cons (subseq line 0 pos)
                 (parse-with-delimiter (subseq line (1+ pos)) delim)))
          (t
           (list line)))))

(defun parse-with-delimiters (line &optional (delimiters '(#\newline)))
  "Breaks LINE into a list of strings, using DELIMITERS as a 
   breaking point."
  ;; what about #\return instead of #\newline?
  (let ((pos (position-if #'(lambda (character) (find character delimiters))
			    line)))
    (cond (pos
           (cons (subseq line 0 pos)
                 (parse-with-delimiters (subseq line (1+ pos)) delimiters)))
          (t
           (list line)))))

(defun string-search-car (character-bag string)
  "Returns the part of the string before the first of the delimiters in 
   CHARACTER-BAG and the delimiter."
  (let* ((delimiter nil)
	 (delimiter-position (position-if #'(lambda (character)
					      (when (find character 
							  character-bag)
						(setq delimiter character)))
					  string)))
    (values (subseq string 0 delimiter-position)
	    delimiter)))

(defun string-search-cdr (character-bag string)
  "Returns the part of the string after the first of the delimiters in 
   CHARACTER-BAG, if any, and the delimiter. If none of the delimiters 
   are found, returns NIL and NIL."
  (let* ((delimiter nil)
	 (delimiter-position (position-if #'(lambda (character)
					      (when (find character 
							  character-bag)
						(setq delimiter character)))
					 string)))
    (if delimiter-position
	(values (subseq string (1+ delimiter-position))
		delimiter)
	;; Maybe this should be "" instead of NIL?
	(values nil delimiter))))