1

I have a file, myfile.txt, whose content is:

(query-replace "foo" "Hello" nil (point-min) (poin-max))

and this function:

(defun comment-string-from-file ()
  (interactive)
  (let ((STRING (with-temp-buffer 
           (insert-file-contents "myfile.txt")
           (buffer-string))))

    (when (string-match (regexp-quote STRING) (buffer-string))
      (let ((b (copy-marker (match-beginning 0)))
        (e (copy-marker (match-end 0))))

    (comment-region b e)))))

This function works and, if present, comments, in the current buffer, the string:

"(query-replace \"foo\" \"Hello\" nil (point-min) (poin-max))"

Now I'd like to do the same thing looping over a file that contains a list of strings, separated by 2 newlines, e.g.

(query-replace "foo" "Hello" nil (point-min) (poin-max))

(query-replace "bar" "World" nil (point-min) (poin-max))

(insert "foo\n")

(insert "bar\n")

Alternatively, and this should be my first choice, I could use an arbitrary string boundary to allow newlines in my strings, e.g..

♦(query-replace "foo" 
           "Hello" nil (point-min) (poin-max))♦

♦(query-replace "bar" 
           "World" nil (point-min) (poin-max))♦

♦(insert "foo\n")♦

♦(insert "bar\n")♦

The idea is that I don't want to use any kind of escaping in the source file.

How can I do it?

  • This feels a bit convoluted, and I'm not sure I understand correctly what the output is supposed to be. I can see that the input is the contents of myfile.txt, but can you please show the resulting contents of the output buffer (as you would like it to appear)? – phils Mar 2 at 21:23
  • Ah, I see now. myfile.txt is a set of patterns, and you want to match those patterns in the current buffer (whatever that is), and comment out the matching regions. – phils Mar 2 at 21:28
  • @phils Yes. I want to comment the matching regions. I'll use it in temp-buffer. I need it to "filter" a file to ignoring/inhibiting some regions to be executed. – Gabriele Nicolardi Mar 2 at 21:37
2

The following Elisp function covers all your use-cases. You can choose two newlines as separator regexp sep. That is the default. Or you can also choose some other character as separator regexp, such as . Empty strings between two separators are removed from the list string-list of regexps matching patterns to be commented-out. So your alternative pattern file syntax should work.

The patterns are combined to one regexp through regexp-opt. You can comment all occurrences of the patterns by calling comment-string-from-file with prefix arg. Otherwise only the first occurrence of each pattern is replaced (such as your code example indicates).

(require 'cl-lib)
(defun comment-string-from-file (file &optional sep all)
  "Read patterns separated by SEP from FILE, comment out matching regions.
Comment all matches if ALL is non-nil.
Comment only first one if ALL is nil."
  (interactive "fPattern file: \nsSeparator regexp: \nP")
  (unless sep
    (setq sep "\n\n+"))
  (let* ((string (with-temp-buffer
                   (insert-file-contents file)
                   (buffer-string)))
         (string-list (cl-remove-if
                       (lambda (str)
                         (string-match "\\`[[:space:]\n]*\\'" str))
                       (split-string string sep)))
         (re (regexp-opt string-list)))
    (save-excursion
      (goto-char (point-min))
      (while (and
              string-list
              (re-search-forward re nil t))
        (let ((match (match-string 0)))
          (comment-region
           (match-beginning 0)
           (match-end 0))
          (unless all
            (setq string-list (cl-remove match string-list :test #'string-equal)
                  re (regexp-opt string-list))))))))
| improve this answer | |
  • Thank you. I'll study it carefully! Do I need a common lisp package? – Gabriele Nicolardi Mar 2 at 23:39
  • @GabrieleNicolardi I have added (require 'cl-lib). That is all you need from cl. – Tobias Mar 2 at 23:43
  • [[:space:]\n] could probably also be [[:blank:]], and (lambda (str) (string-match ...)) could probably be #'string-blank-p from subr-x.el. – Basil Mar 3 at 10:34
  • @Basil No, [[:blank:]] matches horizontal whitespace. Newline is explicitly excluded: unicode.org/reports/tr18/tr18-19.html#blank – Tobias Mar 3 at 10:53
  • @Tobias Oops, right you are. In that case shouldn't you also include \r, as per string-blank-p? – Basil Mar 3 at 11:02

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.