Skip to main content
Minor: grammer in docstring.
Source Link
Malle Yeno
  • 493
  • 1
  • 4
  • 16
(defun search-repeating-N-words ()
"Search buffer for repeating phrases with N number of words."
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of thosethe last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))

(defun search-repeating-N-words ()
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of those last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))

(defun search-repeating-N-words ()
"Search buffer for repeating phrases with N number of words."
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of the last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))

Clarification on how I understand the problem.
Source Link
Malle Yeno
  • 493
  • 1
  • 4
  • 16

(In other words, something similar to what writing assistant programs do to improve writing quality by reducing repeated phrases. We don't know what said phrases are ahead of time.)

We can implement a function like this using regex to search for each phrase with word lengthwords N:

(defun search-repeating-N-words ()
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute, even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of those last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))

(In other words, something similar to what writing assistant programs do to improve writing quality by reducing repeated phrases.)

We can implement a function like this using regex to search for each phrase with word length N:

(defun search-repeating-N-words ()
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute, even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of those last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))

(In other words, something similar to what writing assistant programs do to improve writing quality by reducing repeated phrases. We don't know what said phrases are ahead of time.)

We can implement a function like this using regex to search for each phrase with words N:

(defun search-repeating-N-words ()
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of those last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))

Source Link
Malle Yeno
  • 493
  • 1
  • 4
  • 16

To start: This question might need more detail/clarification. On my first reading of the question, I believed the OP was asking for a general search function (ex. If find or regex was fed a sequence of 5 words, it would display all the matches.)

If I do not interpret the desired as a general search, then I believe you are asking for the function, given N as input, to iteratively:

  1. If there are N words at point and ahead, take them as input. If not, return output and exit.
  2. Capture the search results of this input within the document as output.
  3. Move forward one word.

(In other words, something similar to what writing assistant programs do to improve writing quality by reducing repeated phrases.)

I am unsure of what the desired output is. For simplicity, the output is a set of marks pushed to the mark ring. This way, you can use the mark ring to iterate through the results for editing/viewing as is best suited to whichever use case you have.

We can implement a function like this using regex to search for each phrase with word length N:

(defun search-repeating-N-words ()
  (interactive)
  (let (N x regex-search)
    (setq N (read-number "How many words to search?: " 5))
    (setq x 1)
    (save-excursion
      ;; The search at the end will execute, even if there aren't N words left.
      ;; Given that it only searches forward, this is inefficient but not erroneous.
      (while (< x (length (buffer-string))
                (save-excursion
                        (let (p1 p2 (case-fold-search t))
                          (setq p1 x)
                          ;; After search N words forward,
                          ;; set end point as index of those last char of those words
                          (dotimes (y N (setq p2 (point)))
                              (skip-chars-forward "_a-z0-9"))

                          (setq regex-search
                             (buffer-substring-no-properties p1 p2)))

                      ;; Only forward search is necessary. If it was repeated behind,
                      ;; we would have caught it in the previous iterations.
                      ;; For the record, this implementation does introduce
                      ;; the problem where the same repeated phrase is
                      ;; captured by multiple earlier searches.
                      (save-excursion
                        (while (search-forward regex-search nil t)
                          (let (p2)
                           (setq p2 (point))
                           (goto-char (- p2 (length regex-search)))
                           (push-mark p2))))

                      (setq x (+ x (skip-chars-forward "_a-zA-Z0-9") 1))))))))