eatloaf
eatloaf

Reputation: 617

in emacs-lisp, how do I correctly use replace-regexp-in-string?

Given a string, I want to replace all links within it with the link's description. For example, given

this is a [[http://link][description]]

I would like to return

this is a description

I used re-builder to construct this regexp for a link:

\\[\\[[^\\[]+\\]\\[[^\\[]+\\]\\]

This is my function:

(defun flatten-string-with-links (string)
    (replace-regexp-in-string "\\[\\[[^\\[]+\\]\\[[^\\[]+\\]\\]"
                (lambda(s) (nth 2 (split-string s "[\]\[]+"))) string))

Instead of replacing the entire regexp sequence, it only replaces the trailing "]]". This is what it produces:

this is a [[http://link][descriptiondescription

I don't understand what's going wrong. Any help would be much appreciated.

UPDATE: I've improved the regex for the link. It's irrelevant to the question but if someone's gonna copy it they may as well get the better version.

Upvotes: 5

Views: 1855

Answers (1)

nelhage
nelhage

Reputation: 2784

Your problem is that split-string is clobbering the match data, which replace-regexp-in-string is relying on being unchanged, since it is going to go use that match data to decide which sections of the string to cut out. This is arguably a doc bug in that replace-regexp-in-string does not mention that your replacement function must preserve the match data.

You can work around by using save-match-data, which is a macro provided for exactly this purpose:

(defun flatten-string-with-links (string)
    (replace-regexp-in-string "\\[\\[[a-zA-Z:%@/\.]+\\]\\[[a-zA-Z:%@/\.]+\\]\\]"
                (lambda (s) (save-match-data
                         (nth 2 (split-string s "[\]\[]+")))) string))

Upvotes: 7

Related Questions