如何在 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)
我如何编写一个正则表达式来匹配行中的 ,
但不匹配 ""
中的内容?
例如:
`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)