使用(?:x)|(?:y)重新搜索后退不起作用?

时间:2013-12-09 17:56:55

标签: regex emacs elisp

我正在尝试从comint-mode派生一个低级模式,自动“链接”输出中file:line:col的两个变体。

为此,我有一个正则表达式,在非捕获组中有两个子模式,由|加入。每个子模式都有三个捕获组:

(concat
  "\\(?:" ;; pattern 1  e.g. "; /path/to/file:1:1"
    "; \\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)"
  "\\)"
  "\\|"
  "\\(?:" ;; pattern 2  e.g. "location:  #(<path:/path/to/file> 0 1"
    "location:   (#<path:\\([^>]+\\)> \\([0-9]+\\) \\([0-9]+\\)"
  "\\)")

匹配与第一个子模式匹配的内容。但它从不匹配与第二个子模式匹配的内容。

然而,第一个模式的存在似乎意味着第二个(?: ...)模式永远不会匹配。如果我注释掉第一个模式,那么第二个模式将匹配。

如果我删除第一个子模式,请离开

  "\\(?:" ;; pattern 2
    "location:   (#<path:\\([^>]+\\)> \\([0-9]+\\) \\([0-9]+\\)"
  "\\)"

确实匹配,所以我知道第二个子模式是正确的。

或者,如果我保留第一个子模式,但将其更改为类似“XXX”,没有捕获:

  "\\(?:" ;; pattern 1
    "XXXX"
  "\\)"
  "\\|"
  "\\(?:" ;; pattern 2
    "location:   (#<path:\\([^>]+\\)> \\([0-9]+\\) \\([0-9]+\\)"
  "\\)"

它也有效。第一个子模式与不包含“XXXX”的示例输入不匹配,第二个子模式接下来尝试匹配。

我很难过。我是否误解了一般的regexp,或者这对Emacs来说是独一无二的吗?


更重要的背景:

(define-derived-mode inferior-foo-mode comint-mode "Inferior Foo"
  ...
  (add-hook 'comint-output-filter-functions 'linkify)
  ...)

(defun linkify (str)
  (save-excursion
    (end-of-buffer)
    (re-search-backward (concat
                         "\\(?:" ;; pattern 1
                           "; \\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)"
                         "\\)"
                         "\\|"
                         "\\(?:" ;; pattern 2
                           "location:   (#<path:\\([^>]+\\)> \\([0-9]+\\) \\([0-9]+\\)"
                         "\\)")
                        (- (buffer-size) (length str))
                        t)
    (when (and (match-beginning 0)
               (match-beginning 1) (match-beginning 2) (match-beginning 3))
      (make-text-button
       (match-beginning 1) (match-end 3)
       'file (buffer-substring-no-properties (match-beginning 1) (match-end 1))
       'line (buffer-substring-no-properties (match-beginning 2) (match-end 2))
       'col  (buffer-substring-no-properties (match-beginning 3) (match-end 3))
       'action #'go-to-file-line-col
       'follow-link t))))

2 个答案:

答案 0 :(得分:2)

你错了。第二个非捕获组的捕获组是(match-string 4)(match-string 5)(match-string 6)

另请注意,

(buffer-substring-no-properties (match-beginning 1) (match-end 1))

相当于简短版本

(match-string-no-properties 1)

我会建议像:

(let ((m1 (or (match-string-no-properties 1) (match-string-no-properties 4)))
      (m2 (or (match-string-no-properties 2) (match-string-no-properties 5)))
      (m2 (or (match-string-no-properties 3) (match-string-no-properties 6))))
     (when (and m1 m2 m3) ...

答案 1 :(得分:2)

您的正则表达式与其评论不符。

评论有#(;正则表达式为(#。评论在location:之后有两个空格;正则表达式有3个空格。如果你使它们对应,那么它似乎工作正常。 E.g:

(concat
 "\\(?:" ;; pattern 1
 "; \\([^:]+\\):\\([0-9]+\\):\\([0-9]+\\)"
 "\\)"
 "\\|"
 "\\(?:" ;; pattern 2
 "location:  #(<path:\\([^>]+\\)> \\([0-9]+\\) \\([0-9]+\\)"
 "\\)")