如何在 Elisp 中使用正则表达式来匹配行中但不在引号内的 ','

How to use regexp in Elisp to match ',' in the line but not inside quotation mark

我如何编写一个正则表达式来匹配行中的 , 但不匹配 "" 中的内容?

例如:

`uvm_info("body", $sformatf("Value: a = %d, b = %d, c = %d", a, b, c), UVM_MEDIUM)

希望匹配下^的:

`uvm_info("body", $sformatf("Value: a = %d, b = %d, c = %d", a, b, c), UVM_MEDIUM)
                ^                                          ^  ^  ^   ^

试试这个

"[^"]+"|(,)

捕获组 1

中的

您可以使用 font-lock 首先将注释和字符串字体化,然后应用您的 font-lock 关键字这一事实。

标准解决方案是将您的正则表达式替换为搜索正则表达式的函数,并跳过注释和字符串中的任何匹配项。

下面是我的包lisp-extra-font-lock(高亮显示被let、引用表达式等绑定的变量的包)它搜索引号和反引号,但原理是一样的:

(defun lisp-extra-font-lock-is-in-comment-or-string ()
  "Return non-nil if point is in comment or string.

This assumes that Font Lock is active and has fontified comments
and strings."
  (let ((props (text-properties-at (point)))
        (faces '()))
    (while props
      (let ((pr (pop props))
            (value (pop props)))
        (if (eq pr 'face)
            (setq faces value))))
    (unless (listp faces)
      (setq faces (list faces)))
    (or (memq 'font-lock-comment-face faces)
        (memq 'font-lock-string-face faces)
        (memq 'font-lock-doc-face faces))))


(defun lisp-extra-font-lock-match-quote-and-backquote (limit)
  "Search for quote and backquote in in code.
Set match data 1 if character matched is backquote."
  (let (res)
    (while (progn (setq res (re-search-forward "\(?:\(`\)\|'\)" limit t))
                  (and res
                       (or
                        (lisp-extra-font-lock-is-in-comment-or-string)
                        ;; Don't match ?' and ?`.
                        (eq (char-before (match-beginning 0)) ??)))))
    res))

font-lock关键字如下:

(;; Quote and backquote.
 ;;
 ;; Matcher: Set match-data 1 if backquote.
 lisp-extra-font-lock-match-quote-and-backquote
 (1 lisp-extra-font-lock-backquote-face nil t)
 ;; ...)

以下函数不使用正则表达式,而是将缓冲区区域解析为 sexps 和 returns 所有逗号的缓冲区位置列表,不包括字符串中的逗号,或 nil如果没有这样的逗号。

(defun find-commas (start end)
  (save-excursion
    (goto-char start)
    (let (matches)
      (while (< (point) end)
        (cond ((= (char-after) ?,)
               (push (point) matches)
               (forward-char))
              ((looking-at "[]\[{}()]")
               (forward-char))
              (t
               (forward-sexp))))
      (nreverse matches))))

它适用于您展示的示例,但可能需要针对其他示例或语言进行调整。如果您的示例本身位于缓冲区中,则调用

(find-commas (point-min) (point-max))

returns

(17 60 63 66 70)