aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2021-08-16 13:20:35 +0200
committerLars Ingebrigtsen2021-08-16 13:20:35 +0200
commit751f1707f009c714dbfe047ef43443a5c0c3df89 (patch)
treeaf4841befe93c09b6e28851fa5c20e57be9abbc5
parent42be41657813ae606427aa53d2f0f0b7039d3ef1 (diff)
downloademacs-751f1707f009c714dbfe047ef43443a5c0c3df89.tar.gz
emacs-751f1707f009c714dbfe047ef43443a5c0c3df89.zip
Add new functions to replace strings/regexp in a region
* doc/lispref/searching.texi (Search and Replace): Document them. * lisp/subr.el (replace-string-in-region) (replace-regexp-in-region): New functions. * lisp/emacs-lisp/shortdoc.el (regexp, buffer): Mention them.
-rw-r--r--doc/lispref/searching.texi26
-rw-r--r--etc/NEWS6
-rw-r--r--lisp/emacs-lisp/shortdoc.el6
-rw-r--r--lisp/subr.el61
-rw-r--r--test/lisp/subr-tests.el46
5 files changed, 139 insertions, 6 deletions
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index 1d3e2d986c5..fe47e7ccf57 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -2540,9 +2540,9 @@ associated with it still exists.
2540@cindex replacement after search 2540@cindex replacement after search
2541@cindex searching and replacing 2541@cindex searching and replacing
2542 2542
2543 If you want to find all matches for a regexp in part of the buffer, 2543 If you want to find all matches for a regexp in part of the buffer
2544and replace them, the best way is to write an explicit loop using 2544and replace them, the most flexible way is to write an explicit loop
2545@code{re-search-forward} and @code{replace-match}, like this: 2545using @code{re-search-forward} and @code{replace-match}, like this:
2546 2546
2547@example 2547@example
2548(while (re-search-forward "foo[ \t]+bar" nil t) 2548(while (re-search-forward "foo[ \t]+bar" nil t)
@@ -2553,9 +2553,23 @@ and replace them, the best way is to write an explicit loop using
2553@xref{Replacing Match,, Replacing the Text that Matched}, for a 2553@xref{Replacing Match,, Replacing the Text that Matched}, for a
2554description of @code{replace-match}. 2554description of @code{replace-match}.
2555 2555
2556 However, replacing matches in a string is more complex, especially 2556@findex replace-regexp-in-region
2557if you want to do it efficiently. So Emacs provides two functions to do 2557 If it's more convenient, you can also use the
2558this. 2558@code{replace-regexp-in-region}, which does something similar to the
2559loop above, but is optionally delimited to a specific region (and
2560doesn't change point). Furthermore, it does the searches
2561case-sensitively, and performs the replacements without changing case
2562in the replacement.
2563
2564@example
2565(replace-regexp-in-region "foo[ \t]+bar" "foobar")
2566@end example
2567
2568@findex replace-string-in-region
2569 There's also @code{replace-string-in-region}, which works along the
2570same lines, but searches for literal strings instead.
2571
2572 Emacs also has special functions for replacing matches in a string.
2559 2573
2560@defun replace-regexp-in-string regexp rep string &optional fixedcase literal subexp start 2574@defun replace-regexp-in-string regexp rep string &optional fixedcase literal subexp start
2561This function copies @var{string} and searches it for matches for 2575This function copies @var{string} and searches it for matches for
diff --git a/etc/NEWS b/etc/NEWS
index c2b53e47050..54168e82660 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2443,6 +2443,12 @@ images are marked.
2443 2443
2444** Miscellaneous 2444** Miscellaneous
2445 2445
2446+++
2447*** New function 'replace-regexp-in-region'.
2448
2449+++
2450*** New function 'replace-string-in-region'.
2451
2446--- 2452---
2447*** New function 'mail-header-parse-addresses-lax'. 2453*** New function 'mail-header-parse-addresses-lax'.
2448This takes a comma-separated string and returns a list of mail/name 2454This takes a comma-separated string and returns a list of mail/name
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 1b0fbfdf715..7d4a69f42a9 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -700,6 +700,8 @@ There can be any number of :example/:result elements."
700 (match-substitute-replacement 700 (match-substitute-replacement
701 :no-eval (match-substitute-replacement "new") 701 :no-eval (match-substitute-replacement "new")
702 :eg-result "new") 702 :eg-result "new")
703 (replace-regexp-in-region
704 :no-value (replace-regexp-in-region "[0-9]+" "Num \\&"))
703 "Utilities" 705 "Utilities"
704 (regexp-quote 706 (regexp-quote
705 :eval (regexp-quote "foo.*bar")) 707 :eval (regexp-quote "foo.*bar"))
@@ -894,6 +896,10 @@ There can be any number of :example/:result elements."
894 :no-value (erase-buffer)) 896 :no-value (erase-buffer))
895 (insert 897 (insert
896 :no-value (insert "This string will be inserted in the buffer\n")) 898 :no-value (insert "This string will be inserted in the buffer\n"))
899 (subst-char-in-region
900 :no-eval "(subst-char-in-region (point-min) (point-max) ?+ ?-)")
901 (replace-string-in-region
902 :no-value (replace-string-in-region "foo" "bar"))
897 "Locking" 903 "Locking"
898 (lock-buffer 904 (lock-buffer
899 :no-value (lock-buffer "/tmp/foo")) 905 :no-value (lock-buffer "/tmp/foo"))
diff --git a/lisp/subr.el b/lisp/subr.el
index 1cae3ee1a60..0a31ef2b29f 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3859,6 +3859,67 @@ Point in BUFFER will be placed after the inserted text."
3859 (with-current-buffer buffer 3859 (with-current-buffer buffer
3860 (insert-buffer-substring current start end)))) 3860 (insert-buffer-substring current start end))))
3861 3861
3862(defun replace-string-in-region (string replacement &optional start end)
3863 "Replace STRING with REPLACEMENT in the region from START to END.
3864The number of replaced occurrences are returned, or nil if STRING
3865doesn't exist in the region.
3866
3867If START is nil, use the current point. If END is nil, use `point-max'.
3868
3869Comparisons and replacements are done with fixed case."
3870 (if start
3871 (when (< start (point-min))
3872 (error "Start before start of buffer"))
3873 (setq start (point)))
3874 (if end
3875 (when (> end (point-max))
3876 (error "End after end of buffer"))
3877 (setq end (point-max)))
3878 (save-excursion
3879 (let ((matches 0)
3880 (case-fold-search nil))
3881 (goto-char start)
3882 (while (search-forward string end t)
3883 (delete-region (match-beginning 0) (match-end 0))
3884 (insert replacement)
3885 (setq matches (1+ matches)))
3886 (and (not (zerop matches))
3887 matches))))
3888
3889(defun replace-regexp-in-region (regexp replacement &optional start end)
3890 "Replace REGEXP with REPLACEMENT in the region from START to END.
3891The number of replaced occurrences are returned, or nil if REGEXP
3892doesn't exist in the region.
3893
3894If START is nil, use the current point. If END is nil, use `point-max'.
3895
3896Comparisons and replacements are done with fixed case.
3897
3898REPLACEMENT can use the following special elements:
3899
3900 `\\&' in NEWTEXT means substitute original matched text.
3901 `\\N' means substitute what matched the Nth `\\(...\\)'.
3902 If Nth parens didn't match, substitute nothing.
3903 `\\\\' means insert one `\\'.
3904 `\\?' is treated literally."
3905 (if start
3906 (when (< start (point-min))
3907 (error "Start before start of buffer"))
3908 (setq start (point)))
3909 (if end
3910 (when (> end (point-max))
3911 (error "End after end of buffer"))
3912 (setq end (point-max)))
3913 (save-excursion
3914 (let ((matches 0)
3915 (case-fold-search nil))
3916 (goto-char start)
3917 (while (re-search-forward regexp end t)
3918 (replace-match replacement t)
3919 (setq matches (1+ matches)))
3920 (and (not (zerop matches))
3921 matches))))
3922
3862(defun yank-handle-font-lock-face-property (face start end) 3923(defun yank-handle-font-lock-face-property (face start end)
3863 "If `font-lock-defaults' is nil, apply FACE as a `face' property. 3924 "If `font-lock-defaults' is nil, apply FACE as a `face' property.
3864START and END denote the start and end of the text to act on. 3925START and END denote the start and end of the text to act on.
diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el
index b57982a7055..21b8a27858e 100644
--- a/test/lisp/subr-tests.el
+++ b/test/lisp/subr-tests.el
@@ -694,5 +694,51 @@ See https://debbugs.gnu.org/cgi/bugreport.cgi?bug=19350."
694 (should-not (buffer-local-boundp 'test-not-boundp buf)) 694 (should-not (buffer-local-boundp 'test-not-boundp buf))
695 (should (buffer-local-boundp 'test-global-boundp buf)))) 695 (should (buffer-local-boundp 'test-global-boundp buf))))
696 696
697(ert-deftest test-replace-string-in-region ()
698 (with-temp-buffer
699 (insert "foo bar zot foobar")
700 (should (= (replace-string-in-region "foo" "new" (point-min) (point-max))
701 2))
702 (should (equal (buffer-string) "new bar zot newbar")))
703
704 (with-temp-buffer
705 (insert "foo bar zot foobar")
706 (should (= (replace-string-in-region "foo" "new" (point-min) 14)
707 1))
708 (should (equal (buffer-string) "new bar zot foobar")))
709
710 (with-temp-buffer
711 (insert "foo bar zot foobar")
712 (should-error (replace-string-in-region "foo" "new" (point-min) 30)))
713
714 (with-temp-buffer
715 (insert "Foo bar zot foobar")
716 (should (= (replace-string-in-region "Foo" "new" (point-min))
717 1))
718 (should (equal (buffer-string) "new bar zot foobar"))))
719
720(ert-deftest test-replace-regexp-in-region ()
721 (with-temp-buffer
722 (insert "foo bar zot foobar")
723 (should (= (replace-regexp-in-region "fo+" "new" (point-min) (point-max))
724 2))
725 (should (equal (buffer-string) "new bar zot newbar")))
726
727 (with-temp-buffer
728 (insert "foo bar zot foobar")
729 (should (= (replace-regexp-in-region "fo+" "new" (point-min) 14)
730 1))
731 (should (equal (buffer-string) "new bar zot foobar")))
732
733 (with-temp-buffer
734 (insert "foo bar zot foobar")
735 (should-error (replace-regexp-in-region "fo+" "new" (point-min) 30)))
736
737 (with-temp-buffer
738 (insert "Foo bar zot foobar")
739 (should (= (replace-regexp-in-region "Fo+" "new" (point-min))
740 1))
741 (should (equal (buffer-string) "new bar zot foobar"))))
742
697(provide 'subr-tests) 743(provide 'subr-tests)
698;;; subr-tests.el ends here 744;;; subr-tests.el ends here