Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I capture the results of splitting a string in elisp?

Tags:

regex

emacs

elisp

I am working in elisp and I have a string that represents a list of items. The string looks like

"apple orange 'tasty things' 'my lunch' zucchini 'my dinner'"

and I'm trying to split it into

("apple" "orange" "tasty things" "my lunch" "zucchini" "my dinner")

This is a familiar problem. My obstacles to solving it are less about the regex, and more about the specifics of elisp.

What I want to do is run a loop like :

  • (while (< (length my-string) 0) do-work)

where that do-work is:

  • applying the regex \('[^']*?'\|[[:alnum:]]+)\([[:space:]]*\(.+\) to my-string
  • appending \1 to my results list
  • re-binding my-string to \2

However, I can't figure out how to get split-string or replace-regexp-in-string to do that.

How can I split this string into values I can use?

(alternatively: "which built-in emacs function that does this have I not yet found?")

like image 806
Brighid McDonnell Avatar asked Dec 06 '25 04:12

Brighid McDonnell


1 Answers

Something similar, but w/o regexp:

(defun parse-quotes (string)
  (let ((i 0) result current quotep escapedp word)
    (while (< i (length string))
      (setq current (aref string i))
      (cond
       ((and (char-equal current ?\ )
             (not quotep))
        (when word (push word result))
        (setq word nil escapedp nil))
       ((and (char-equal current ?\')
             (not escapedp) 
             (not quotep))
        (setq quotep t escapedp nil))
       ((and (char-equal current ?\')
             (not escapedp))
        (push word result)
        (setq quotep nil word nil escapedp nil))
       ((char-equal current ?\\)
        (when escapedp (push current word))
        (setq escapedp (not escapedp)))
       (t (setq escapedp nil)
        (push current word)))
      (incf i))
    (when quotep
      (error (format "Unbalanced quotes at %d"
                     (- (length string) (length word)))))
    (when word (push result word))
    (mapcar (lambda (x) (coerce (reverse x) 'string))
            (reverse result))))

(parse-quotes "apple orange 'tasty things' 'my lunch' zucchini 'my dinner'")
("apple" "orange" "tasty things" "my lunch" "zucchini" "my dinner")

(parse-quotes "apple orange 'tasty thing\\'s' 'my lunch' zucchini 'my dinner'")
("apple" "orange" "tasty thing's" "my lunch" "zucchini" "my dinner")

(parse-quotes "apple orange 'tasty things' 'my lunch zucchini 'my dinner'")
;; Debugger entered--Lisp error: (error "Unbalanced quotes at 52")

Bonus: it also allows escaping the quotes with "\" and will report it if the quotes aren't balanced (reached the end of the string, but didn't find the match for the opened quote).