0

I have functions that run re-search-forward and gather its output into a buffer.

(defun my-search (pattern)
  "Uses `re-search-forward` to return matching lines."
  (let ((src)
    (rslt))
    (progn 
      (goto-char (re-search-forward pattern))
      (save-excursion
       (setq rslt (buffer-substring (progn (beginning-of-line-text)(point))
                    (progn (end-of-line) (point)))))
      (format "%s\n\n" rslt))))


(defun my-search-results ()
"Iterate through buffer with `my-search` and gather matching lines into a buffer."
  (interactive)
    (let ((pattern (read-regexp "Regex Pattern to Search for: "))
    (rslt (generate-new-buffer "*Search Results*"))
    (match 0)
    (nlines 0)
    (current-line 0))
        (while (not (eq (ignore-errors (save-excursion (re-search-forward pattern))) nil))
    (princ (my-search pattern) rslt)
    (incf match))
    (switch-to-buffer "*Search Results*")))

We all know that Occur will display "%d matches in %d lines." in its search result. How do we do the same for these functions without repetition when there is more than one match in a line?

Currently, match would keep track of the number of iteration cycles, which should be equivalent to the number of matching pattern found.

Adding an if clause to my-search-results doesn't solve the problem.

(defun my-search-results ()
  (interactive)
    (let ((pattern (read-regexp "Regex Pattern to Search for: "))
    (rslt (generate-new-buffer "*Search Results*"))
    (match 0)
    (nlines 0)
    (current-line 0))
        (beginning-of-buffer)
        (while (not (eq (ignore-errors (save-excursion (re-search-forward pattern))) nil))
    (princ (my-search pattern) rslt)
    (incf nlines)
    (incf match)
    (if (= (line-number-at-pos)
           (save-excursion
         (progn
           (re-search-forward pattern)
           (point))))
        (progn (re-search-forward pattern)
           (incf match))))
    (message "%d matches in %d lines." match nlines)
    (switch-to-buffer "*Search Results*")))


Test Data:

abacd
efgja
ogjfh

Desired Outcome:

M-xmy-search-results a

;; Result: 
;; abacd
;; efgja

;; 3 matches in 2 lines.

1 Answer 1

1

I took your code as base and rewrote it somewhat.
The following function is one possible solution to solve that problem in one function:

(defun my-search-results (pattern)
  (interactive (list (read-regexp "Regex Pattern to Search for: ")))
  (let ((result-buffer (generate-new-buffer "*Search Results*"))
        (matches 0)
        (lines 0)
        (last-printed-line -1))
    (save-excursion
      (beginning-of-buffer)
      (while (re-search-forward pattern nil t)
        (incf matches)
        (let ((line-number-at-pos (line-number-at-pos)))
          (unless (= line-number-at-pos last-printed-line)
            (incf lines)
            (setq last-printed-line line-number-at-pos)
            (princ (thing-at-point 'line t) result-buffer)))))
    (switch-to-buffer "*Search Results*")
    (message "%d matches in %d lines." matches lines)))

Notes about changes:

  • I moved save-excursion out of the loop, because this function call is expensive and would slow down the loop without benefit. This is also responsible, that point is locatet at the last match and I can get the current line number
  • I compare current line number with the last printed line number to decide weather to increase lines and print, or not.
  • I used thing-at-point to get the current line as a string
  • I used available parameters of re-search-forward to suppress errors.
4
  • Is there a way to indicate cases where there is more than one match in a line? I tried changing the unless clause to if so that I can princ a standard text to indicate that, but wasn't able to make it work.
    – Sati
    Commented Feb 18, 2020 at 16:45
  • (let ((line-number-at-pos (line-number-at-pos))) seems like a smart way to make use of the same function symbol as a variable so that that line-number-at-pos can become the last-printed-line.
    – Sati
    Commented Feb 18, 2020 at 16:59
  • 1
    @Sati of course it is possible. Changing the unless to if is the right action. But changes depend on, what you want to print. If it is the number of occurences per line, before the line, then bigger changes would be necessary. You can use edebug to step through this function, to see how it works.
    – jue
    Commented Feb 18, 2020 at 17:02
  • @sati line-number-at-pos thats one of the benefits of a lisp-2 language.
    – jue
    Commented Feb 18, 2020 at 17:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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