Nhận tất cả các kết quả khớp lại trong bộ đệm dưới dạng danh sách


18

Trên trang web Code Golf Stack Exchange hôm nay, tôi đã tìm thấy câu trả lời này trong Clojure cho câu hỏi "Nhận tất cả các liên kết trên một trang web".

(->> (slurp "http://www.stroustrup.com")
     (re-seq #"(?:http://)?www(?:[./#\+-]\w*)+"))

Không có macro ưa thích, nó chỉ như thế này:

(re-seq #"(?:http://)?www(?:[./#\+-]\w*)+" (slurp "http://www.stroustrup.com"))

Điều này trả về danh sách:

("http://www.morganstanley.com/" "http://www.cs.columbia.edu/" "http://www.cse.tamu.edu" ...)

Tôi có thể làm điều gì đó tương tự trong Emacs Lisp không?

Có lẽ một chức năng như (re-seq regexp (buffer-string))vậy trả về '(firstmatch secondmatch thirdmatch ...)?


Đây là những gì M-x occurhiện có, nhưng tôi sẽ tìm bên trong các chức năng cấp thấp hơn để làm điều đó.
wvxvw

@wvxvw Đó là một điểm tốt, tôi thậm chí không nghĩ về occur. Tôi sẽ phải xem qua nguồn của nó.
mẫu

Tôi nhìn vào bên trong, và ôi chao, mã đó làm quá nhiều và không dễ để tái sử dụng nó, không hề. Ứng cử viên tiếp theo của tôi sẽ là s.el, nhưng có lẽ có nhiều hơn ngoài đó. Ở đây: github.com/magnars/s.el#s-match-strings-all-regex-opes làm thế nào về điều này?
wvxvw

Câu trả lời:


16

Đây là cách bạn có thể làm điều đó dựa trên chuỗi, theo yêu cầu.

(defun re-seq (regexp string)
  "Get a list of all regexp matches in a string"
  (save-match-data
    (let ((pos 0)
          matches)
      (while (string-match regexp string pos)
        (push (match-string 0 string) matches)
        (setq pos (match-end 0)))
      matches)))

; Sample URL
(setq urlreg "\\(?:http://\\)?www\\(?:[./#\+-]\\w*\\)+")
; Sample invocation
(re-seq urlreg (buffer-string))

Điều đó có vẻ không hoàn chỉnh, bạn có thể mở rộng câu trả lời này thành một câu trả lời đầy đủ không?
wasamasa

1
Mã đã hoàn thành, nhưng tôi cũng đã thêm một ví dụ về việc sử dụng. Bạn còn muốn xem gì nữa không?
Alan Shutko

1
Giải pháp này quá đơn giản, thật không may. Hãy thử (re-seq "^.*$" ""). Regex hợp lệ, chuỗi hợp lệ, nhưng nó không bao giờ chấm dứt.
Phil Lord

8

Có lẽ đáng lưu ý rằng việc gọi occurvới đối số phổ quát sẽ khiến nó chỉ điền vào *Occur*bộ đệm - không có tên tệp, số dòng hoặc thông tin tiêu đề. Khi kết hợp với một nhóm chụp, điều này cho phép một người trích xuất bất kỳ mẫu nào mong muốn.

Ví dụ, C-u M-x occurtheo sau \"\(.*\)\"sẽ nhắc người dùng sẽ thu thập nhóm chụp (mặc định \1), sau đó đặt nội dung của mỗi chuỗi được trích dẫn vào *Occur*bộ đệm.


5

Tôi có một câu trả lời không thể thiếu cho câu hỏi đó được đăng: /codegolf//a/44319/18848

Sử dụng cùng cấu trúc (while (tìm kiếm) (in)), bạn có thể sửa đổi nó thành một hàm để đẩy các kết quả khớp trong bộ đệm vào danh sách và trả về nó như sau:

(defun matches-in-buffer (regexp &optional buffer)
  "return a list of matches of REGEXP in BUFFER or the current buffer if not given."
  (let ((matches))
    (save-match-data
      (save-excursion
        (with-current-buffer (or buffer (current-buffer))
          (save-restriction
            (widen)
            (goto-char 1)
            (while (search-forward-regexp regexp nil t 1)
              (push (match-string 0) matches)))))
      matches)))

Nice câu trả lời, lưu ý bạn có thể muốn thay thế match-stringvới match-string-no-propertiesquá nổi bật cú pháp không tách ra. Bạn có thể muốn vượt qua regexp-group-indexđể sử dụng để bạn có thể chọn văn bản nào được lưu trữ. Cũng như đảo ngược thứ tự tìm kiếm (danh sách hiện tại là từ cuối đến trước). Xem câu trả lời này bao gồm một phiên bản sửa đổi emacs.stackexchange.com/a/38752/2418
ideaman42

3

Sử dụng s.elcái này sẽ ngắn hơn, nhưng thật không may, nó cho quá nhiều trận đấu:

(defun all-urls-in-buffer ()
  (s-match-strings-all
   "\\(?:http://\\)?www\\(?:[./#+-]\\w*\\)+"
   (buffer-string)))

Nếu điều này ổn (dù sao thì regex cho URL không hoàn hảo), điều này có thể ngắn hơn và nếu không, thì tôi không nghĩ mình có thể rút ngắn hơn câu trả lời của Alan Shutko.


2

Hãy để tôi chỉ đề cập đến lý do tại sao tôi nghĩ rằng điều này không được thực hiện trong cốt lõi. Đơn giản vì lý do hiệu quả: không cần phải sao chép, tạo danh sách, chuyển chúng xung quanh và thu gom rác. Thay vào đó, lưu trữ toàn bộ chuỗi dưới dạng bộ đệm và hoạt động với giới hạn khớp số nguyên. Đó là cách occurhoạt động, ví dụ: nó khớp một chuỗi tại một thời điểm và chèn trận đấu vào *occur*. Nó không khớp tất cả các chuỗi cùng một lúc, đưa chúng vào danh sách, lặp trong danh sách để chèn vào *occur*và thu thập danh sách và chuỗi của nó.

Giống như bạn sẽ không viết (do (def x 1) (def x (+ 2 x)))bằng Clojure, theo mặc định, bạn không nên cố gắng để Elisp hoạt động như một ngôn ngữ chức năng. Tôi thích nó nếu có, nhưng chúng tôi phải làm theo những gì chúng tôi có vào lúc này.


1

Nếu tôi có thể được phép cắm, hãy xem thư viện "m-buffer" của tôi.

(m-buffer-match buffer "foo")

Trả về một danh sách các điểm đánh dấu để phù hợp với foo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.