From fdeb1a3dc77ccac28e6cf91b9cc4aa43f3060e7a Mon Sep 17 00:00:00 2001 From: dalanicolai Date: Sat, 8 May 2021 13:59:03 +0200 Subject: Mention that Emacs is usually case-insensitive in a couple of places * doc/lispref/searching.texi (Regular Expressions): Mention `case-fold-search'. * lisp/emacs-lisp/re-builder.el (re-builder): Mention case sensitivity toggles (bug#47534). Copyright-paperwork-exempt: yes --- doc/lispref/searching.texi | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'doc/lispref/searching.texi') diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index 16a8e56e90a..99451d0bc66 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -251,6 +251,11 @@ matches in the target buffer are highlighted. Each parenthesized sub-expression of the regexp is shown in a distinct face, which makes it easier to verify even very complex regexps. + Note that by default Emacs search ignores case (@xref{Searching and +Case}). To enable case-sensitive regexp search and match, bind +@code{case-fold-search} to @code{nil} around the code you want to be +case-sensitive. + @menu * Syntax of Regexps:: Rules for writing regular expressions. * Regexp Example:: Illustrates regular expression syntax. -- cgit v1.2.3 From d3344e0a7fc9435910a600d831ebdb8b2953b2a5 Mon Sep 17 00:00:00 2001 From: "Basil L. Contovounesios" Date: Sat, 8 May 2021 15:07:38 +0100 Subject: ; Fix recent re-builder doc changes. --- doc/lispref/searching.texi | 2 +- lisp/emacs-lisp/re-builder.el | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'doc/lispref/searching.texi') diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index 99451d0bc66..b38ee995abe 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -251,7 +251,7 @@ matches in the target buffer are highlighted. Each parenthesized sub-expression of the regexp is shown in a distinct face, which makes it easier to verify even very complex regexps. - Note that by default Emacs search ignores case (@xref{Searching and + Note that by default Emacs search ignores case (@pxref{Searching and Case}). To enable case-sensitive regexp search and match, bind @code{case-fold-search} to @code{nil} around the code you want to be case-sensitive. diff --git a/lisp/emacs-lisp/re-builder.el b/lisp/emacs-lisp/re-builder.el index b695dff55a4..7d042a9102e 100644 --- a/lisp/emacs-lisp/re-builder.el +++ b/lisp/emacs-lisp/re-builder.el @@ -346,7 +346,7 @@ matching parts of the target buffer will be highlighted. Case-sensitivity can be toggled with \\[reb-toggle-case]. The regexp builder supports three different forms of input which can be set with \\[reb-change-syntax]. More options and details are -provided in the initial comment of`re-builder.el'." +provided in the Commentary section of this library." (interactive) (if (and (string= (buffer-name) reb-buffer) (reb-mode-buffer-p)) -- cgit v1.2.3 From 5dfa5e26dd58c6e8aa135c81ecfdbda92725556e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 30 May 2021 13:20:02 +0300 Subject: Improve documentation of regexp ranges * doc/lispref/searching.texi (Regexp Special): Document the effect of using octal escapes in regexp ranges. (Bug#17758) --- doc/lispref/searching.texi | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'doc/lispref/searching.texi') diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index 8b900da616f..1ee4be7dd13 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -363,7 +363,7 @@ preceding expression either once or not at all. For example, @anchor{Non-greedy repetition} @item @samp{*?}, @samp{+?}, @samp{??} @cindex non-greedy repetition characters in regexp -These are @dfn{non-greedy} variants of the operators @samp{*}, @samp{+} +are @dfn{non-greedy} variants of the operators @samp{*}, @samp{+} and @samp{?}. Where those operators match the largest possible substring (consistent with matching the entire containing expression), the non-greedy variants match the smallest possible substring @@ -438,6 +438,13 @@ including newline. However, a reversed range should always be from the letter @samp{z} to the letter @samp{a} to make it clear that it is not a typo; for example, @samp{[+-*/]} should be avoided, because it matches only @samp{/} rather than the likely-intended four characters. + +@item +If the end points of a range are raw 8-bit bytes (@pxref{Text +Representations}), or if the range start is ASCII and the end is a raw +byte (as in @samp{[a-\377]}), the range will match only ASCII +characters and raw 8-bit bytes, but not non-ASCII characters. This +feature is intended for searching text in unibyte buffers and strings. @end enumerate Some kinds of character alternatives are not the best style even -- cgit v1.2.3 From 751f1707f009c714dbfe047ef43443a5c0c3df89 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Mon, 16 Aug 2021 13:20:35 +0200 Subject: 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. --- doc/lispref/searching.texi | 26 ++++++++++++++----- etc/NEWS | 6 +++++ lisp/emacs-lisp/shortdoc.el | 6 +++++ lisp/subr.el | 61 +++++++++++++++++++++++++++++++++++++++++++++ test/lisp/subr-tests.el | 46 ++++++++++++++++++++++++++++++++++ 5 files changed, 139 insertions(+), 6 deletions(-) (limited to 'doc/lispref/searching.texi') 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. @cindex replacement after search @cindex searching and replacing - If you want to find all matches for a regexp in part of the buffer, -and replace them, the best way is to write an explicit loop using -@code{re-search-forward} and @code{replace-match}, like this: + If you want to find all matches for a regexp in part of the buffer +and replace them, the most flexible way is to write an explicit loop +using @code{re-search-forward} and @code{replace-match}, like this: @example (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 @xref{Replacing Match,, Replacing the Text that Matched}, for a 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 two functions to do -this. +@findex replace-regexp-in-region + If it's more convenient, you can also use the +@code{replace-regexp-in-region}, which does something similar to the +loop above, but is optionally delimited to a specific region (and +doesn't change point). Furthermore, it does the searches +case-sensitively, and performs the replacements without changing case +in the replacement. + +@example +(replace-regexp-in-region "foo[ \t]+bar" "foobar") +@end example + +@findex replace-string-in-region + There's also @code{replace-string-in-region}, which works along the +same lines, but searches for literal strings instead. + + Emacs also has special functions for replacing matches in a string. @defun replace-regexp-in-string regexp rep string &optional fixedcase literal subexp start This 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. ** Miscellaneous ++++ +*** New function 'replace-regexp-in-region'. + ++++ +*** New function 'replace-string-in-region'. + --- *** New function 'mail-header-parse-addresses-lax'. This 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." (match-substitute-replacement :no-eval (match-substitute-replacement "new") :eg-result "new") + (replace-regexp-in-region + :no-value (replace-regexp-in-region "[0-9]+" "Num \\&")) "Utilities" (regexp-quote :eval (regexp-quote "foo.*bar")) @@ -894,6 +896,10 @@ There can be any number of :example/:result elements." :no-value (erase-buffer)) (insert :no-value (insert "This string will be inserted in the buffer\n")) + (subst-char-in-region + :no-eval "(subst-char-in-region (point-min) (point-max) ?+ ?-)") + (replace-string-in-region + :no-value (replace-string-in-region "foo" "bar")) "Locking" (lock-buffer :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." (with-current-buffer buffer (insert-buffer-substring current start end)))) +(defun replace-string-in-region (string replacement &optional start end) + "Replace STRING with REPLACEMENT in the region from START to END. +The number of replaced occurrences are returned, or nil if STRING +doesn't exist in the region. + +If START is nil, use the current point. If END is nil, use `point-max'. + +Comparisons and replacements are done with fixed case." + (if start + (when (< start (point-min)) + (error "Start before start of buffer")) + (setq start (point))) + (if end + (when (> end (point-max)) + (error "End after end of buffer")) + (setq end (point-max))) + (save-excursion + (let ((matches 0) + (case-fold-search nil)) + (goto-char start) + (while (search-forward string end t) + (delete-region (match-beginning 0) (match-end 0)) + (insert replacement) + (setq matches (1+ matches))) + (and (not (zerop matches)) + matches)))) + +(defun replace-regexp-in-region (regexp replacement &optional start end) + "Replace REGEXP with REPLACEMENT in the region from START to END. +The number of replaced occurrences are returned, or nil if REGEXP +doesn't exist in the region. + +If START is nil, use the current point. If END is nil, use `point-max'. + +Comparisons and replacements are done with fixed case. + +REPLACEMENT can use the following special elements: + + `\\&' in NEWTEXT means substitute original matched text. + `\\N' means substitute what matched the Nth `\\(...\\)'. + If Nth parens didn't match, substitute nothing. + `\\\\' means insert one `\\'. + `\\?' is treated literally." + (if start + (when (< start (point-min)) + (error "Start before start of buffer")) + (setq start (point))) + (if end + (when (> end (point-max)) + (error "End after end of buffer")) + (setq end (point-max))) + (save-excursion + (let ((matches 0) + (case-fold-search nil)) + (goto-char start) + (while (re-search-forward regexp end t) + (replace-match replacement t) + (setq matches (1+ matches))) + (and (not (zerop matches)) + matches)))) + (defun yank-handle-font-lock-face-property (face start end) "If `font-lock-defaults' is nil, apply FACE as a `face' property. START 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." (should-not (buffer-local-boundp 'test-not-boundp buf)) (should (buffer-local-boundp 'test-global-boundp buf)))) +(ert-deftest test-replace-string-in-region () + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-string-in-region "foo" "new" (point-min) (point-max)) + 2)) + (should (equal (buffer-string) "new bar zot newbar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-string-in-region "foo" "new" (point-min) 14) + 1)) + (should (equal (buffer-string) "new bar zot foobar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should-error (replace-string-in-region "foo" "new" (point-min) 30))) + + (with-temp-buffer + (insert "Foo bar zot foobar") + (should (= (replace-string-in-region "Foo" "new" (point-min)) + 1)) + (should (equal (buffer-string) "new bar zot foobar")))) + +(ert-deftest test-replace-regexp-in-region () + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-regexp-in-region "fo+" "new" (point-min) (point-max)) + 2)) + (should (equal (buffer-string) "new bar zot newbar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should (= (replace-regexp-in-region "fo+" "new" (point-min) 14) + 1)) + (should (equal (buffer-string) "new bar zot foobar"))) + + (with-temp-buffer + (insert "foo bar zot foobar") + (should-error (replace-regexp-in-region "fo+" "new" (point-min) 30))) + + (with-temp-buffer + (insert "Foo bar zot foobar") + (should (= (replace-regexp-in-region "Fo+" "new" (point-min)) + 1)) + (should (equal (buffer-string) "new bar zot foobar")))) + (provide 'subr-tests) ;;; subr-tests.el ends here -- cgit v1.2.3 From f0ef1e971d200940f5ebf1d50707112df659da8e Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 16 Aug 2021 20:11:33 +0300 Subject: Fix recent documentation additions * doc/lispref/searching.texi (Search and Replace): Document the new functions by @defun. --- doc/lispref/searching.texi | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) (limited to 'doc/lispref/searching.texi') diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi index fe47e7ccf57..4d5ae3cb437 100644 --- a/doc/lispref/searching.texi +++ b/doc/lispref/searching.texi @@ -2553,21 +2553,31 @@ using @code{re-search-forward} and @code{replace-match}, like this: @xref{Replacing Match,, Replacing the Text that Matched}, for a description of @code{replace-match}. -@findex replace-regexp-in-region - If it's more convenient, you can also use the -@code{replace-regexp-in-region}, which does something similar to the -loop above, but is optionally delimited to a specific region (and -doesn't change point). Furthermore, it does the searches -case-sensitively, and performs the replacements without changing case -in the replacement. + It may be more convenient to limit the replacements to a specific +region. The function @code{replace-regexp-in-region} does that. + +@defun replace-regexp-in-region regexp replacement &optional start end +This function replaces all the occurrences of @var{regexp} with +@var{replacement} in the region of buffer text between @var{start} and +@var{end}; @var{start} defaults to position of point, and @var{end} +defaults to the last accessible position of the buffer. The search +for @var{regexp} is case-sensitive, and @var{replacement} is inserted +without changing its letter-case. The @var{replacement} string can +use the same special elements starting with @samp{\} as +@code{replace-match} does. The function returns the number of +replaced occurrences, or @code{nil} if @var{regexp} is not found. The +function preserves the position of point. @example (replace-regexp-in-region "foo[ \t]+bar" "foobar") @end example +@end defun -@findex replace-string-in-region - There's also @code{replace-string-in-region}, which works along the -same lines, but searches for literal strings instead. +@defun replace-string-in-region string replacement &optional start end + This function works similarly to @code{replace-regexp-in-region}, +but searches for, and replaces, literal @var{string}s instead of +regular expressions. +@end defun Emacs also has special functions for replacing matches in a string. -- cgit v1.2.3