Emacs Lisp: сопоставление повторяющегося шаблона в компактной форме? - PullRequest
5 голосов
/ 02 февраля 2012

Предположим, у меня есть строка RGB (формат: # <2 шестнадцатеричные цифры> <2 шестнадцатеричные цифры> <2 шестнадцатеричные цифры>), например:

"#00BBCC"

, и я хотел бы сопоставить изахватывать его элементы <2 шестнадцатеричных чисел> более компактным способом, чем при использовании очевидных:

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

Я пробовал:

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

и:

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

Но больше всего они соответствовали первому элементу <2 шестнадцатеричных цифр>.

Есть идеи?Спасибо.

Ответы [ 2 ]

4 голосов
/ 02 февраля 2012

Вы можете сделать регулярное выражение короче за счет некоторого дополнительного кода:

(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 голос
/ 04 февраля 2012

Если вы хотите захватить R, G, B в разных подгруппах, чтобы вы могли извлечь их, используя (match-string group), вам нужно иметь три различные группы скобок в регулярном выражении в некоторый момент.

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

В противном случае, если вы используете шаблон повторения, такой как

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

, у вас есть только одна группа, и после совпадения она будет содержать только значение последнего совпадения.Так, скажем, если у вас есть что-то вроде

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

, это будет соответствовать строке типа «A0B1C2», но (match-string 1) будет содержать только содержимое последнего соответствия, то есть «C2»,потому что регулярное выражение определяет только одну группу.

Таким образом, у вас в основном есть два варианта: использовать компактное регулярное выражение, такое как ваше третье, но выполнить дополнительную обработку подстроки, чтобы извлечь шестнадцатеричное число, как предлагает Шон, или использоватьболее сложное регулярное выражение, такое как ваше первое, которое позволяет вам более удобно получать доступ к трем подсовпадениям.

Если вас больше всего беспокоит читаемость кода, вы всегда можете сделать что-то вроде

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

чтобы построить такое более сложное регулярное выражение несколько менее избыточным способом, согласно предложению тройника.

...