2016-11-05 40 views
2

在elisp中,我如何獲得正則表達式匹配的解構綁定?正則表達式匹配的解構綁定

例如,

;; what is the equivalent of this with destructuring? 
(with-temp-buffer 
    (save-excursion (insert "a b")) 
    (re-search-forward "\\(a\\) \\(b\\)") 
    (cons (match-string 1) 
     (match-string 2))) 

;; trying to do something like the following 
(with-temp-buffer 
    (save-excursion (insert "a b")) 
    (cl-destructuring-bind (a b) (re-search-forward "\\(a\\) \\(b\\)") 
    (cons a b))) 

我想我會寫一個宏來擴大比賽如果沒有另一種方式。

+0

我不認爲這個問題是有道理的。 're-search-forward'本身並不會返回與您想要執行的操作相關的數據結構,所以我沒有看到任何嘗試在此處使用解構綁定的目的。只要堅持你的原始代碼? – phils

回答

3

這裏有一種方法:你第一次延長pcase接受一個新的re-match模式,用一個定義,如:

(pcase-defmacro re-match (re) 
    "Matches a string if that string matches RE. 
RE should be a regular expression (a string). 
It can use the special syntax \\(?VAR: to bind a sub-match 
to variable VAR. All other subgroups will be treated as shy. 

Multiple uses of this macro in a single `pcase' are not optimized 
together, so don't expect lex-like performance. But in order for 
such optimization to be possible in some distant future, back-references 
are not supported." 
    (let ((start 0) 
     (last 0) 
     (new-re '()) 
     (vars '()) 
     (gn 0)) 
    (while (string-match "\\\\(\\(?:\\?\\([-[:alnum:]]*\\):\\)?" re start) 
     (setq start (match-end 0)) 
     (let ((beg (match-beginning 0)) 
      (name (match-string 1 re))) 
     ;; Skip false positives, either backslash-escaped or within [...]. 
     (when (subregexp-context-p re start last)   
      (cond 
      ((null name) 
      (push (concat (substring re last beg) "\\(?:") new-re)) 
      ((string-match "\\`[0-9]" name) 
      (error "Variable can't start with a digit: %S" name)) 
      (t 
      (let* ((var (intern name)) 
        (id (cdr (assq var vars)))) 
       (unless id 
       (setq gn (1+ gn)) 
       (setq id gn) 
       (push (cons var gn) vars)) 
       (push (concat (substring re last beg) (format "\\(?%d:" id)) 
        new-re)))) 
      (setq last start)))) 
    (push (substring re last) new-re) 
    (setq new-re (mapconcat #'identity (nreverse new-re) "")) 
    `(and (pred stringp) 
      (app (lambda (s) 
       (save-match-data 
        (when (string-match ,new-re s) 
        (vector ,@(mapcar (lambda (x) `(match-string ,(cdr x) s)) 
             vars))))) 
       (,'\` [,@(mapcar (lambda (x) (list '\, (car x))) vars)]))))) 

,一旦做到這一點,你可以按如下方式使用它:

(pcase X 
    ((re-match "\\(?var:[[:alpha:]]*\\)=\\(?val:.*\\)") 
    (cons var val))) 

(pcase-let 
    (((re-match "\\(?var:[[:alpha:]]*\\)=\\(?val:.*\\)") X)) 
    (cons var val)) 

這還沒有被大量的測試,正如文檔字符串中提到的那樣,當同時將字符串與各種正則表達式匹配時,它不會像它(c | sh)那樣有效。你也只能得到匹配的子串,而不是它們的位置。最後,它將正則表達式搜索應用於字符串,而在manny /大多數情況下,正則表達式搜索用於緩衝區中。但是你可能仍然覺得它很有用。

+0

真棒回答:)非常感謝 – jenesaisquoi