Tüm regexp maçlarını arabellekte bir liste olarak al


18

Bugün Code Golf Stack Exchange sitesinde, bu cevabı Clojure'da "Bir web sayfasındaki tüm linkleri al" sorusuna buldum .

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

Süslü makro olmadan, sadece bu:

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

Bu listeyi döndürür:

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

Emacs Lisp'de benzer bir şey yapabilir miyim?

Belki böyle bir işlev (re-seq regexp (buffer-string))geri döner '(firstmatch secondmatch thirdmatch ...)?


İşte M-x occurbu, ama bunu yapmak için daha düşük seviyeli fonksiyonlar için içeriye bakardım.
wvxvw

@wvxvw Bu iyi bir nokta, düşünmedim bile occur. Kaynağına bakmam gerekecek.
dadı

İçeriye baktım ve oh woe, bu kod çok şey yapıyor ve onu yeniden yapmak kolay değil, hiç de değil. Bir sonraki adayım olurdu s.el, ama belki daha fazlası var. İşte: github.com/magnars/s.el#s-match-strings-all-regex-string buna ne dersiniz?
wvxvw

Yanıtlar:


16

İstendiği gibi dizelere dayalı olarak bunu nasıl yapabileceğiniz aşağıda açıklanmıştır.

(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))

Bu tam değil gibi görünüyor, bunu tamamen çalışan bir cevaba genişletebilir misiniz?
wasamasa

1
Kod tamamlandı, ancak bir kullanım örneği de ekledim. Başka ne görmek istersiniz?
Alan Shutko

1
Bu çözüm maalesef çok basit. Deneyin (re-seq "^.*$" ""). Geçerli normal ifade, geçerli dize, ancak hiçbir zaman sonlandırılmaz.
Phil Lord

8

occurEvrensel argümanla çağırmanın , *Occur*arabelleği yalnızca eşleşmelerle doldurmasına neden olduğunu belirtmek gerekir - dosya adı, satır numarası veya başlık bilgisi yok. Bir yakalama grubu ile kombine edildiğinde, bu arzu edilen herhangi bir paternin çıkarılmasını sağlar.

Örneğin, C-u M-x occurardından, \"\(.*\)\"hangi yakalama grubunun toplanacağı (varsayılan \1) kullanıcıdan bilgi istenir ve ardından alıntı yapılan her dizenin içeriği *Occur*arabelleğe yerleştirilir.


5

Şu soruya bir emacs lisp cevabım var: /codegolf//a/44319/18848

Aynı (while (search) (print)) yapısını kullanarak, arabellekteki eşleşmeleri bir listeye itmek ve şöyle döndürmek için bir işleve değiştirebilirsiniz:

(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)))

Güzel cevap, not değiştirmek isteyebilirsiniz match-stringile match-string-no-propertiessözdizimi vurgulama çıkarılan değildir bu yüzden. regexp-group-indexHangi metnin saklanacağını seçebilmeniz için a işaretini kullanmak isteyebilirsiniz . Arama sırasını tersine çevirmenin yanı sıra (geçerli liste sondan başa doğrudur). Değiştirilmiş bir sürümü içeren bu cevaba bakın emacs.stackexchange.com/a/38752/2418
ideasman42

3

s.elBunu kullanmak daha kısa olurdu, ancak maalesef çok fazla eşleşme veriyor:

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

Bu tamamsa (URL'ler için normal ifade zaten mükemmel değildir), bu sadece daha kısa olabilir ve eğer değilse, o zaman Alan Shutko'nun cevabından daha kısa yapabileceğimi sanmıyorum.


2

Bunun neden özünde uygulanmadığını düşündüğümü açıklayayım. Sadece verimlilik nedeniyle: kopyalamaya, liste oluşturmaya, bunları aktarmaya ve çöpleri toplamaya gerek yoktur. Bunun yerine, dizenin tamamını arabellek olarak saklayın ve tamsayı eşleme sınırları ile çalıştırın. İşte böyle occuro maç içine zaman ve ekler az bir dizeyle eşleşir: eserler, örneğin *occur*. Tüm dizeleri aynı anda eşleştirmez, onları listeye dönüştürür, eklemek için listede döngü yapar *occur*ve listeyi ve dizelerini çöp toplar.

Tıpkı (do (def x 1) (def x (+ 2 x)))Clojure'da yazmayacağınız gibi, Elisp'in varsayılan olarak işlevsel bir dil gibi davranmasını denememelisiniz. Öyle olsaydı çok isterdim, ama şu anda sahip olduğumuz şeyleri yapmak zorundayız.


1

Fişe izin verilebilirse, "m-buffer" kütüphaneme bir göz atın.

(m-buffer-match buffer "foo")

Eşleşecek işaretçilerin bir listesini döndürür foo.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.