]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new, simple `replace-in-string' function
authorLars Ingebrigtsen <larsi@gnus.org>
Tue, 15 Sep 2020 14:50:44 +0000 (16:50 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Tue, 15 Sep 2020 15:15:59 +0000 (17:15 +0200)
* lisp/subr.el (replace-in-string): New, side-effect-free function.

* doc/lispref/searching.texi (Search and Replace): Document it.

doc/lispref/searching.texi
etc/NEWS
lisp/subr.el
test/lisp/subr-tests.el

index b6242c539b70fbc2b8c62c3d272438d8e994dfee..a217c6e9358e879ec92d7f8e4cf7ee4079b6c49c 100644 (file)
@@ -2542,7 +2542,7 @@ and replace them, the best way is to write an explicit loop using
 description of @code{replace-match}.
 
   However, replacing matches in a string is more complex, especially
-if you want to do it efficiently.  So Emacs provides a function to do
+if you want to do it efficiently.  So Emacs provides two functions to do
 this.
 
 @defun replace-regexp-in-string regexp rep string &optional fixedcase literal subexp start
@@ -2564,6 +2564,11 @@ passing the text of the match as its sole argument.  It collects the
 value @var{rep} returns and passes that to @code{replace-match} as the
 replacement string.  The match data at this point are the result
 of matching @var{regexp} against a substring of @var{string}.
+@end defun
+
+@defun replace-in-string fromstring tostring instring
+This function copies @var{instring} and replaces any occurrences of
+@var{fromstring} with @var{tostring}.
 @end defun
 
   If you want to write a command along the lines of @code{query-replace},
index 2928fd9d97022c47f33e33bfe46fb7c49e7241a9..c9221a2284dddf6382bcf4cfb7d321dd2ad0b05e 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1317,6 +1317,12 @@ ledit.el, lmenu.el, lucid.el and old-whitespace.el.
 \f
 * Lisp Changes in Emacs 28.1
 
++++
+*** New function 'replace-in-string'.
+This function works along the line of 'replace-regexp-in-string', but
+matching on strings instead of regexps, and does not change the global
+match state.
+
 ---
 *** 'ascii' is now a coding system alias for 'us-ascii'.
 
index b1537fd27a60b189fa27570d18b1daf21a328089..b8331760e340c1a9415f7cf2c451ec0c47dd17b3 100644 (file)
@@ -4411,6 +4411,36 @@ Unless optional argument INPLACE is non-nil, return a new string."
          (aset newstr i tochar)))
     newstr))
 
+(defun replace-in-string (fromstring tostring instring)
+  "Replace FROMSTRING with TOSTRING in INSTRING each time it occurs.
+This function returns a freshly created string."
+  (declare (side-effect-free t))
+  (let ((i 0)
+        (start 0)
+        (result nil))
+    (while (< i (length instring))
+      (if (eq (aref instring i)
+              (aref fromstring 0))
+          ;; See if we're in a match.
+          (let ((ii i)
+                (if 0))
+            (while (and (< ii (length instring))
+                        (< if (length fromstring))
+                        (eq (aref instring ii)
+                            (aref fromstring if)))
+              (setq ii (1+ ii)
+                    if (1+ if)))
+            (when (= if (length fromstring))
+              (when (not (= start i))
+                (push (substring instring start i) result))
+              (push tostring result)
+              (setq i ii
+                    start ii)))
+        (setq i (1+ i))))
+    (when (not (= start i))
+      (push (substring instring start i) result))
+    (apply #'concat (nreverse result))))
+
 (defun replace-regexp-in-string (regexp rep string &optional
                                        fixedcase literal subexp start)
   "Replace all matches for REGEXP with REP in STRING.
index 2df5537102f8f02c92834491e46cca62f5e64a83..8bec097aadf3cd6195c125850912ba0077ad269a 100644 (file)
@@ -440,5 +440,17 @@ See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19350."
   (should-error (ignore-error foo
                   (read ""))))
 
+(ert-deftest replace-in-string ()
+  (should (equal (replace-in-string "foo" "bar" "zot")
+                 "zot"))
+  (should (equal (replace-in-string "foo" "bar" "foozot")
+                 "barzot"))
+  (should (equal (replace-in-string "foo" "bar" "barfoozot")
+                 "barbarzot"))
+  (should (equal (replace-in-string "zot" "bar" "barfoozot")
+                 "barfoobar"))
+  (should (equal (replace-in-string "z" "bar" "barfoozot")
+                 "barfoobarot")))
+
 (provide 'subr-tests)
 ;;; subr-tests.el ends here