I was trying to use this code shared by @JordonBiondo over here to collect regex matches in a list.

(defun matches-in-buffer (regexp &optional buffer)
  "return a list of matches of REGEXP in BUFFER or the current buffer if not given."
  (let ((matches))
        (with-current-buffer (or buffer (current-buffer))
            (goto-char 1)
            (while (search-forward-regexp regexp nil t 1)
              (push (match-string 0) matches)))))

When we run this code:

(print (format "%s"
 (matches-in-buffer "//select/items/[A-Z_0-9]+" (current-buffer)))))

We get a nice list of matching items printed out below, as expected.

(//select/items/1_7YBDN5YT //select/items/1_8JVACVAG //select/items/1_8JVACVAG)


My question is: How do we print out the elements on the list line by line?


Running the code below results in an error.

(setq rslt
      (format "%s"
              (matches-in-buffer "//select/items/[A-Z_0-9]+" (current-buffer))))

(defun print-elements-of-list (list)
  "Print each element of LIST on a line of its own."
  (while list
    (print (car list))
    (setq list (cdr list))))

(print-elements-of-list rslt)


(wrong-type-argument listp "(//select/items/1_7YBDN5YT //select/items/1_8JVACVAG //select/items/1_8JVACVAG)")

Sample Data:

* Lorem Ipsum

Lorem ipsum dolor sit amet, consectetur adipiscing elit. [fn:105d40022edca6cb:This is a footnote with citations. [[//select/items/1_8JVACVAG][Author,Title]],pp.502-2. ]Phasellus vitae luctus risus, nec porta est. Nunc ut turpis quam. Phasellus at porta justo, non pellentesque ante. Mauris volutpat egestas tristique. Proin rhoncus diam at diam tincidunt vestibulum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Quisque gravida gravida lorem, ullamcorper porta sem auctor non. Nullam tincidunt maximus rutrum. Fusce nec ante leo. Suspendisse vel rutrum lorem. Donec vitae mattis orci.

Curabitur sed orci fringilla, molestie ex non, venenatis urna. Ut sollicitudin leo eu dolor tincidunt porta. Nullam neque justo, ullamcorper quis ligula fringilla, mollis faucibus elit. Duis at eleifend ligula. [fn:9fc32cc5941ded6: This is another. [[//select/items/1_8JVACVAG][Title]],pp,502-2. ]Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Fusce vel consectetur ligula, eu tempus ipsum. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris et mauris eget odio eleifend lobortis. Nunc non est eros. Morbi scelerisque non libero sit amet egestas. Nullam finibus sagittis dictum. Quisque feugiat, nisl ullamcorper pharetra pretium, quam metus consectetur sapien, in imperdiet purus velit ut nulla. Aenean pretium, ex vitae convallis facilisis, diam eros posuere est, ac consectetur nulla nunc vitae augue. Nullam hendrerit ligula ac nisi malesuada tempor.

Duis sit amet leo ultricies, ullamcorper purus eget, rhoncus ipsum. In hac habitasse platea dictumst. Sed quis sem urna. Maecenas orci magna, eleifend at libero vel, accumsan ornare ipsum. Suspendisse potenti. In tincidunt, neque ut bibendum molestie, augue sapien semper libero, sed pretium odio felis nec mauris. [fn:1d9d0df7958ea454:For a different book see [[//select/items/1_7YBDN5YT][Author, Title]]. ] Aenean nisi quam, semper vel mi nec, hendrerit convallis turpis. Maecenas at rutrum orci, quis ultrices felis. Fusce quis mi dapibus nibh elementum condimentum et id dolor. Sed varius neque eu ante vestibulum dapibus. Sed ac pharetra turpis, a laoreet nunc. Proin dignissim magna nec magna venenatis, eget placerat nunc mollis. Praesent pretium, erat id imperdiet fringilla, nibh dui luctus ligula, at aliquam metus neque quis ex.

  • There is far too much noise in your question. Please edit it to narrow it down to only what is essential/relevant. And please ask only one, specific question per question. – Drew Mar 31 '20 at 17:51

Here's a breakdown of what went wrong:

  • You have a function, matches-in-buffer which returns a list of strings
  • You turn the result of using that function into a string using (format "%s" ...) and assign it to a variable
  • You try to iterate over that variable as if it were a list (it isn't)
  • Emacs tells you that it expected a list, not a string: (wrong-type-argument listp ...)

The correct thing to do here is to take that list and iterate over it. Luckily there's a built-in macro for that, dolist. Here's a cleaned up version of your code:

(let ((matches (matches-in-buffer "//select/items/[A-Z_0-9]+")))
  (dolist (match matches)
    (message "%s" match)))

One more sidenote: You almost never use functions like print, prin1, princ and terpri in code unless you need precise control over where to print. The with-output-to-string and with-output-to-temp-buffer macros are examples of that technique. In all other cases it's easier to use message (display formatted result followed by newline in echo area and messages buffer) and format (return a formatted string) directly.

  • Have you tested your code on the data? It yielded a nil... – Sati Mar 31 '20 at 14:18
  • 2
    That's to be expected for an iteration macro, not returning anything useful. The important part is the messages, check the messages buffer and you'll see them there. – wasamasa Mar 31 '20 at 14:21
  • What if I'd like to print insert the elements at the end of my org buffer? – Sati Mar 31 '20 at 14:27
  • (let ((matches (matches-in-buffer "//select/items/[A-Z_0-9]+"))) (dolist (match matches) (insert (princ (format "%s\n" match))))) This is the code I needed. Thank you! – Sati Mar 31 '20 at 14:30
  • 2
    The combination of princ and (format "%s") is just silly, you're abusing that princ does not only print, but return its value as well. (insert (format "%s\n" match)) will work fine and not print things to the echo area by side effect. – wasamasa Mar 31 '20 at 19:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.