The short answer is: Use (replace-regexp-in-string REGEXP REP STRING)
.
If you want to know how it is done, look at its source code.
Your modified version
EDIT: replacing (setq pos1 (match-end 0)))
with (setq pos1 (+ (match-end 0) (length "newtext1")))
does the job, but it is a trick I find inelegant.
is wrong. It worked in your example by accident. You can use match-beginning
in place of match-end
to get a working version for simple replacement strings. Phils already gave you another fix in his comment.
But if you want to allow for more complicated replacement strings such as group references (as e.g., \1
) you need to do what you really want.
You really want to further process the remaining tail of the string. So determine the tail length and calculate the next position on the basis this length.
You must also care about empty matches. Empty matches may only be treated a finite number of times otherwise you easily get infinite loops. It is most natural to consider empty matches exactly one time.
Essentially they also use these principles in replace-regexp-in-string
. But, they decompose the original string by the matches and compose it back with the replacement strings in place of the matches. That is probably the most efficient method but it makes things a bit nastier.
I give here an alternative implementation demonstrating the principle.
(defun my-replace-regexp-in-string (regexp rep string)
"Alternative version of `replace-regexp-in-string'.
REGEXP, REP, and STRING are the same args as for `replace-regexp-in-string'.
This is just for demonstration. Therefore we do not care about
the optional arguments of `replace-regexp-in-string' here."
(let ((pos 0)
(old-tail-length (length string)))
(catch :empty-match-at-end
(while (string-match regexp string pos)
(let ((tail-length (- (length string) (match-end 0))))
(setq string (replace-match rep nil nil string))
(when (eq tail-length old-tail-length) ;; empty match
(if (zerop tail-length) ;; empty match at the end
(throw :empty-match-at-end nil)
(cl-decf tail-length))) ;; avoid infinite loop
(setq pos (- (length string) tail-length)
old-tail-length tail-length)
))))
string)
;; tests:
(my-replace-regexp-in-string "a" "aa" "bar") ;; Returns "baar"
(my-replace-regexp-in-string "a" "aa" "baar") ;; Returns "baaaar"
(my-replace-regexp-in-string "a+" "\\&b" "baaaar") ;; Returns "baaaabr"
(my-replace-regexp-in-string "a*" "\\&c" "bar") ;; Returns "cbaccrc"
(replace-regexp-in-string regexp1 newtext1 str1)
. If you want to know how it is done look at its source code. It is by far not what you would expect...point
for a string, so you'd need to track it yourself. Or use a buffer, and then you do have apoint
. Buffers are cheap, so if you find this dirty, just don't use string manipulation.