;;AUTOLOAD: replace-string
;;AUTODOC: replace-string "replace regular expression matches in a string"
;;(replace-string string  regexp replacement &key :all :quote :npar :offset)
;;
;;Looks for first occurence of regexp (can be a string) in string and 
;;replaces by the replacement string.
;;The string is modified in place and returned.
;;The number of replacements done is set in the variable replace-string:count
;;Replacement can be:
;;    a string   passed to regsub to expand the \n into matched subparts
;;               (or verbatim if the keyword :quote is set to t)
;;    a vector   used as a p-list to find the remplacement, e.g.:
;;               (replace-string s "[kK]lone" 
;;                               #("Klone" "Lisp" "klone" "lisp"))
;;    anything   is applied to the regexp to return the string to use, you
;;               can use regsub on the regexp to find match details
;;options
;;    :npar N    replace only the N-th substring matched (beginning at the
;;               Nth opening parenthese)
;;               e.g: (replace-string s 
;;                    "(^|[^a-zA-Z_0-9])(foo)($|[^a-zA-Z_0-9])" bar :npar 2)
;;               to replace foo by bar identifiers
;;    :all t     replace ALL the occurences in string
;;    :offset    start offset in string (default 0)
;;    :quote t   do not filter the remplacement string by regsub

(defun replace-string (string regexp replacement 
    &key (npar 0) all (offset 0) ((quote dont-use-regsub))
    &aux 
    (rec (if (typep regexp Regexp) regexp (regcomp regexp)))
    pos
    length-before
  )
  (setq replace-string:count 0)
  (while (regexec rec string offset)
    (setq pos (get rec npar))
    (setq length-before (length string))
    (if (typep replacement String)
      (if dont-use-regsub
	(replace-seq string replacement (get pos 0) (get pos 1))
	(replace-seq string (regsub rec replacement) (get pos 0) (get pos 1))
      )
      (typep replacement Vector)
      (replace-seq string (get replacement (regsub rec npar))
	(get pos 0) (get pos 1))
      t
      (replace-seq string (apply replacement (list rec))
	(get pos 0) (get pos 1))
    )
    (incf replace-string:count)
    (setq offset (if all
	(+ (get pos 1) (- (length string) length-before))
	(length string)			;terminate
    ))      
  )
  string
)
