Short version: If i bound the scope of a search/replace to a region in the buffer (via the second/third optional argument of search-forward and its derivates), how can i match the beginning of that region?

Longer version: Say, i have a test.txt which contains only

xxx yyy xxx xxx yyy xxx xxx yyy xxx xxx yyy xxx xxx yyy xxx
xxx yyy xxx xxx yyy xxx xxx yyy xxx xxx yyy xxx xxx yyy xxx
xxx yyy xxx xxx yyy xxx xxx yyy xxx xxx yyy xxx xxx yyy xxx

Now, I mark any part and like to run M-x query-replace-regexp to replace the first three characters of the marked region. How can i achieve this with a regular expression? A naïve try would be to use

(defun test-1 (b e)
  (interactive "r")
  (query-replace-regexp "^..." "zzz" nil b e)

but ^ matches only bol (and so does \` ), not the beginning of my region. In extension, i need a similar construction in a larger script that could be simplified to the following minimal example:

(defun test-2 ()
  (while (search-forward "xxx xxx" nil t)
    (let ((beg (match-beginning 0))
          (end (match-end 0)))
     (query-replace-regexp "^xxx" "zzz" nil beg end)
     (goto-char (match-end 0)))))

Is there a way to match the beginning of any substring within a regionally bounded regular search?

I am aware that you could avoid the problem by working with narrow-to-region and thus make the beginning of the region the sub-buffer's bol but i'd like to avoid this for the sake of context when I replace stuff in my documents.

  • 1
    While I don't understand your reasoning for avoiding narrowing (narrow, process, widen -- where's the issue?), perhaps you're looking for \= which "matches the empty string, but only at point." Refer to C-h i g (elisp)Regexp Backslash – phils Jun 27 '18 at 8:43
  • I need to see the surrounding context when deciding whether or not to replace a match in my RL case. This is difficult then only the broader match itself is visible. edit: (query-replace-regexp "\=." "z" nil b e) doesn't work, and M-x query-replace-regexp <RET> \=. <RET> z<RET> replaces every character in the region iteratively by z. – Lupino Jun 27 '18 at 8:54
  • 1
    I'm really struggling to fathom what you're trying to achieve here. looking-at would tell you whether there's a regexp match starting from point, and then you can conditionally run your query replace for that same regexp, only if there was a match -- but I don't believe you want to be using a query-replace command at all. It sounds to me like you should query the user yourself, and use replace-match to do the replacement. The query-replace commands are really intended to be called interactively. – phils Jun 27 '18 at 11:16
  • @phils i know. the function test-1 is just for the purpose to illustrate what arguments are given to qrr. The same problem holds by marking a region and calling qrr interactively (which then only matches within said region). For short: I want to access the beginning of this region within the regexp. how do i do that, if possible at all? – Lupino Jun 27 '18 at 12:03
  • 1
    Narrowing (or otherwise extracting and acting on the substring in question) is the only solution I know of. – phils Jun 27 '18 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.