0

I have a a bunch of HTML files and in each of them I want to replace a fixed block of approx 30 lines with a one liner.

Is there an Emacs command or package which makes this easier? Using e.g. dired-do-find-regexp-and-replace is pretty unwieldy for long multi-line search or replacement terms.

7
  • 3
    Can't you match the 30-line block with a specially designed regexp? E.g. a section of text that starts with foo and ends with bar with an arbitrary sequence of (non-newline) chars and newlines can be matched with "foo\\(.*\n\\)*bar". Maybe you can add an example of what your block looks like to the question, but at first sight, it looks straightforward to me. And you can play with re-builder to build a customized regexp that will only match that block and nothing else.
    – NickD
    Oct 18, 2021 at 8:55
  • @NickD Yep, sounds sensible. I was just hoping for something maybe more specialised for this use case…
    – halloleo
    Oct 18, 2021 at 12:48
  • Without more info, this is something I'd use sed/awk/perl, etc for instead of Emacs.
    – nega
    Oct 19, 2021 at 2:36
  • 1
    @nega Thanks. That's actually what I'm doing now. :-)
    – halloleo
    Oct 19, 2021 at 2:41
  • If you're not fixed on using Emacs, there's an answer here. Replace a text block with sed or awk Oct 19, 2021 at 20:01

1 Answer 1

1

It is generally easier to match smaller, specific patterns, and then replace the region between them (although in this case the regexp as suggested by NickD works fine (except for a possible extra required .* before bar). Here follows an example for using a 'start' and 'end' pattern and replacing the region in between in a list of files (single file for this example, but you can add more files to the list) on a unix-like system (on windows just adjust the path names):

First save the following text in a file named ~/test.txt:

this is an example
of how to replace
text in some buffer/file

Then evaluate the following snippet of code:

(dolist (x '("~/test.txt"))
  (with-temp-buffer
    (insert-file-contents-literally x)
    (print (point))
    (search-forward "an")
    (let ((start (match-beginning 0)))
      (delete-region start (search-forward "replace"))
      (goto-char start)
      (insert "the result of replacing"))
    (write-file x)))

Of course, like when using regexps, the start and end patterns must be specific enough to not also replace 'unwanted' other blocks.

B.t.w. if it is a fixed block (i.e. a fixed string), then you could probably also just use replace-string. You could bind the string to a variable for use in replace-string.

Here the original file gets overwritten (for which we could have used with-temp-file directly), but you can replace the final x with something like (concat x ".awesome") to write to new files. I've kept the (print (point)) to show explicitly that the point stays at the start after inserting the file contents. In Emacs, usually editing text is done by inserting it to some buffer, also when doing it programmatically. I hope this answer will be useful for your case...

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.