バッファ内のすべての正規表現の一致をリストとして取得します


18

今日のCode Golf Stack Exchangeサイトで、「Webページ上のすべてのリンクを取得する」という質問に対するClojureのこの回答を見つけました。

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

派手なマクロなしで、それはちょうどこれです:

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

これはリストを返します:

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

Emacs Lispで同様のことができますか?

おそらくそのような関数(re-seq regexp (buffer-string))は返します'(firstmatch secondmatch thirdmatch ...)か?


これが何をするかですM-x occurが、それを行うためのより低レベルの関数を探します。
wvxvw

@wvxvwそれは良い点です、私も考えていませんでしたoccur。そのソースに目を通す必要があります。
乳母

私は中を覗きましたが、あのコードはあまりにも多くのことをしているので、再利用するのは簡単ではありません。私の次の候補者はになりますがs.el、おそらく他にもあるでしょう。ここ:github.com/magnars/s.el#s-match-strings-all-regex-stringこれはどうですか?
wvxvw

回答:


16

要求に応じて、文字列に基づいてそれを行う方法を次に示します。

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

それは完全に見えませんが、これを完全に機能する答えに拡張できますか?
wasamasa

1
コードは完成しましたが、使用例も追加しました。他に何を見たいですか?
アランシュトコ

1
残念ながら、このソリューションは単純すぎます。試してください(re-seq "^.*$" "")。有効な正規表現、有効な文字列ですが、終了することはありません。
フィルロード

8

occur普遍的な引数で呼び出すと、*Occur*ファイル名、行番号、ヘッダー情報なしで一致するものだけがバッファに読み込まれることに注意してください。キャプチャグループと組み合わせると、必要なパターンを抽出できます。

たとえば、次のC-u M-x occurコマンドを実行する\"\(.*\)\"と、収集するキャプチャグループを求めるプロンプトが表示され(デフォルト\1)、引用符で囲まれたすべての文字列のコンテンツが*Occur*バッファーに配置されます。


5

私はその質問に対するemacs lispの回答を投稿しています:https : //codegolf.stackexchange.com/a/44319/18848

同じ(while(検索)(印刷))構造を使用して、バッファ内の一致をリストにプッシュし、次のように返す関数に変更できます。

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

ニースの答えは、置き換えたいことがありますmatch-stringmatch-string-no-properties構文ハイライトが抽出されないようにします。regexp-group-indexどのテキストを保存するかを選択できるように、使用するためにaを渡すことができます。検索の順序を逆にすることもできます(現在のリストは最後から最初です)。変更されたバージョンを含むこの回答を参照してくださいemacs.stackexchange.com/a/38752/2418
ideasman42

3

s.elこれを使用すると短くなりますが、残念ながら、あまりにも多くの一致が得られます。

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

これで問題ない場合(URLの正規表現はとにかく完璧ではありません)、これは短くなる可能性があります。


2

なぜこれがコアに実装されていないと思うのかを言及させてください。単に効率上の理由で:コピー、リストの作成、リストの受け渡し、ガベージコレクションの必要はありません。代わりに、文字列全体をバッファとして保存し、整数の一致境界で動作します。occurたとえば、次のように 動作します。一度に1つの文字列に一致し、その一致をに挿入し*occur*ます。一度にすべての文字列に一致するわけではありません。それらをリストに入れ、リストをループして挿入し *occur*、リストとその文字列をガベージコレクションします。

(do (def x 1) (def x (+ 2 x)))Clojureで書かないのと同じように、デフォルトではElispを関数型言語のように振る舞わせるべきではありません。それがあったらそれが大好きですが、私たちは現時点で持っているものを正当化する必要があります。


1

プラグが許可される場合は、「m-buffer」ライブラリをご覧ください。

(m-buffer-match buffer "foo")

に一致するマーカーのリストを返しますfoo

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.