regex EmacsLisp:以紧凑的方式匹配重复模式?

cld4siwp  于 2023-02-10  发布在  Mac
关注(0)|答案(3)|浏览(114)

假设我有一个RGB字符串(格式:#〈2个十六进制数字〉〈2个十六进制数字〉〈2个十六进制数字〉),如下所示:

"#00BBCC"

我希望以一种比使用显而易见的方法更紧凑的方式匹配和捕获它的〈2 hex digits〉元素:

"#\\([[:xdigit:]\\{2\\}]\\)\\([[:xdigit:]\\{2\\}]\\)\\([[:xdigit:]\\{2\\}]\\)"

我试过了

"#\\([[:xdigit:]]\\{2\\}\\)\\{3\\}"

以及:

"#\\(\\([[:xdigit:]]\\{2\\}\\)\\{3\\}\\)"

但是他们匹配最多的是第一个〈2 hex digits〉元素。
你知道吗?谢谢。

iyfjxgzm

iyfjxgzm1#

您可以以一些额外代码为代价来缩短regexp:

(defun match-hex-digits (str)
  (when (string-match "#[[:xdigit:]]\\{6\\}" str)
    (list (substring (match-string 0 str) 1 3)
          (substring (match-string 0 str) 3 5)
          (substring (match-string 0 str) 5 7))))
cgfeq70w

cgfeq70w2#

如果您想在不同的子组中捕获R、G、B,以便可以使用(match-string group)提取它们,则需要在regexp中有三个不同的括号组。

\(...\)\(...\)\(...\)

否则,如果使用重复图案,如

\(...\)\{3\}

你只有一个组,在匹配之后,它只包含最后一个匹配的值。所以,假设你有沿着于

\([[:xdigit:]]\{2\}\)\{3\}

它将匹配像“A0B1C2”这样的字符串,但是(match-string 1)将只包含最后匹配的内容,即“C2”,因为regexp只定义了一个组。
因此,您基本上有两种选择:使用一个紧凑的regexp(如第三个),但是按照Sean的建议执行更多的子字符串处理来提取十六进制数,或者使用一个更复杂的regexp(如第一个),这样可以更方便地访问三个子匹配。
如果您主要担心代码的可读性,您可以执行以下操作

(let ((hex2 "\\([[:xdigit:]]\\{2\\}\\)"))
  (concat "#" hex2 hex2 hex2))

按照tripleee的建议,以一种稍微少一些冗余的方式构造这样一个更复杂的正则表达式。

wtzytmuj

wtzytmuj3#

在我最初的回应几年后,Emacs有了一个更好的方法来做到这一点,那就是pcase macro

(defun match-hex-digits (str)
  (pcase str
    ((rx "#" (let r (= 2 xdigit)) (let g (= 2 xdigit)) (let b (= 2 xdigit)))
     (list r g b))))

相关问题