Elisp: Find Replace String in Buffer
Search and Find Replace Functions
These search functions are used for search text, and also for find replace:
search-forward
re-search-forward
(using regex)search-backward
re-search-backward
(using regex)
The forward versions place cursor at end of match. The backward versions place cursor at begin of match.
search-forward
-
(search-forward STRING &optional BOUND NOERROR COUNT)
Move cursor forward by searching for given string. Cursor stops at end of matched string.
Alsosearch-backward
. Cursor stops at beginning of matched string.
;; move cursor to the location of cat (search-forward "cat")
re-search-forward
-
(re-search-forward REGEXP &optional BOUND NOERROR COUNT)
Move cursor forward by searching for regex pattern. Cursor stops at end of matched pattern. Return the new position.
Alsore-search-backward
. Cursor stops at beginning of matched string.
[see Emacs: Regex Tutorial]
;; move cursor to the end of a html closing tag (re-search-forward "</[a-z0-9]+>")
Find Replace Text in Buffer
Typical way to do string replacement in current buffer:
(let ((case-fold-search nil)) (goto-char (point-min)) (while (search-forward "myStr1" nil t) (replace-match "myReplaceStr1")) (goto-char (point-min)) (while (search-forward "myStr2" nil t) (replace-match "myReplaceStr2")) ;; repeat for other string pairs )
Case Sensitivity in Search
To control the letter case of search, locally set case-fold-search to t
or nil. By default, it's t.
(let ( (case-fold-search nil) ; case sensitive search ) ;; find replace code here )
Case Sensitivity in Replacement
To control letter case of the replacement, use the optional arguments in replace-match
function.
(replace-match NEWTEXT &optional FIXEDCASE LITERAL STRING SUBEXP)
Use t
for FIXEDCASE.
Match Data
Most functions that take a regex argument, after being called, will save/modify info in “match data”, such as caputured groups, or begin/end positions of the captured pattern, or whole matched pattern.
Match data can be accessed by the function match-data
, and other functions.
However, elisp provide many more direct function to extract data stored in match-data
.
The most useful are match-string
,
match-beginning
, match-end
.
Get Match String
Whenever you call regex functions such as
re-search-forward
,
string-match
,
replace-regexp-in-string
,
the captured text is stored in match-string
.
match-string
(match-string NUM &optional STRING)
Return string of text matched by last search. NUM specifies which parenthesized expression in the last regexp. 0 is the whole pattern. STRING should be given if the last search was bystring-match
on STRING.
;; get the id (re-search-forward "id=\\([a-z0-9]+\\)" ) (message "%s" (match-string 1 )) ;; id=172
Get Begin/End Positions
match-beginning
and match-end
return the begin and end positions of the matched string.
;; get the begin/end positions of the whole regex match (setq pos1 (match-beginning 0)) (setq pos2 (match-end 0))
Find Replace in a Region Boundary
If you need to do find replace on a region only, wrap the code with save-restriction
and narrow-to-region
. Example:
(save-restriction (narrow-to-region pos1 pos2) body )
;; idiom for string replacement within a region (save-restriction (narrow-to-region pos1 pos2) (goto-char (point-min)) (while (search-forward "myStr1" nil t) (replace-match "myReplaceStr1")) ;; repeat for other string pairs )
WARNING: Boundary Change After Insert/Remove text
Whenever you work in a region, remember that the boundaries of the text that you are interested is changed when you add or remove text in that region.
For example, suppose {p1, p2} is the boundary of some text you are interested.
After doing some change there, suppose you want to do some more change.
Don't just call (something-region p1 p2)
again, because p2 is no longer the correct boundary.
A good solution is to use
(narrow-to-region p1 p2)
and use
(point-min)
and
(point-max)
for boundary,
once you narrowed.
Find Replace Multiple Pairs
If you need to find replace multiple pairs frequently, see: Emacs: Xah Replace Pairs, xah-replace-pairs.el.