I'm looking for a function that can replace the nth-match in a string.

Here's an example. 2 is the index of the nth-match, [0-9]+ is the regular expression to search. foo is the replacement and "a 100 b 200 c 300" is the string in which the replacement takes place.

ELISP> (replace-nth-regexp-in-string 2 "[0-9]+" "foo" "a 100 b 200 c 300")
a 100 b foo c 300

I haven't found a built-in expression to do this, so I believe I'll have to write my own. Any advices are appreciated.

  • It'll just be a while loop, to firstly match the regexp N times, and then (provided that was successful) replace-match for the most-recent match data.
    – phils
    Commented Jan 22 at 22:29

1 Answer 1

(setq toto  "a 100 b 200 c 300")

(setq bar  (replace-regexp-in-string "\\(\\([^0-9]+\\)\\([0-9]+\\)\\)\\{2\\}"
                                     "foo" ; Replacement string
                                     toto  ; Input string to match
                                     3))   ; Index of subexp match to replace

toto is unchanged. bar is "a 100 b foo c 300"

The \\{2\\} in the regexp says the match is against two such groups (each of which has two subgroups).

The 3 as argument says replace the 3rd group in the match (the match being the text corresponding to the two matched subgroups).

The first group of the match is the outer group, the second is the group matching non-digits, and the third is the group matching digits.

C-h f replace-regexp-in-string says:

replace-regexp-in-string is a compiled Lisp function in ‘subr.el’.

(replace-regexp-in-string REGEXP REP STRING &optional FIXEDCASE LITERAL SUBEXP START)

Replace all matches for REGEXP with REP in STRING.

Return a new string containing the replacements.

Optional arguments FIXEDCASE, LITERAL and SUBEXP are like the arguments with the same names of function replace-match. If START is non-nil, start replacements at that index in STRING.

REP is either a string used as the NEWTEXT arg of replace-match or a function. If it is a function, it is called with the actual text of each match, and its value is used as the replacement text. When REP is called, the match data are the result of matching REGEXP against a substring of STRING, the same substring that is the actual text of the match which is passed to REP as its argument.

To replace only the first match (if any), make REGEXP match up to \' and replace a sub-expression, e.g.

(replace-regexp-in-string "\\(foo\\).*\\'" "bar" " foo foo" nil nil 1) => " bar foo"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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