Emacs Lisp:以紧凑的方式匹配重复的模式?

时间:2012-02-01 23:41:06

标签: regex emacs elisp

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

"#00BBCC"

我希望匹配并捕获其< 2十六进制数字>元素比使用明显的方式更紧凑:

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

我试过了:

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

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

但他们匹配的最多是第一个< 2十六进制数字>元件。

有什么想法吗?谢谢。

2 个答案:

答案 0 :(得分:4)

您可以以一些额外代码为代价缩短正则表达式:

(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))))

答案 1 :(得分:1)

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

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

否则,如果您使用重复模式,例如

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

您只有一个组,并且在匹配后它将仅包含最后一个匹配的值。所以,比方说,如果你有什么东西沿着

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

它将匹配像“A0B1C2”这样的字符串,但(match-string 1)只包含最后一个匹配的内容,即“C2”,因为正则表达式只定义了一个组。

因此,你基本上有两个选择:使用紧凑的正则表达式,例如你的第三个,但是做一些子串处理来提取肖恩建议的十六进制数,或者使用更复杂的正则表达式,例如你的第一个,让您更方便地访问三个子匹配。

如果您最担心代码可读性,可以随时执行类似

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

根据tripleee的建议,以一种不那么冗余的方式构建这样一个更复杂的正则表达式。