Экранирующий символ (backsla sh) экранируется только от двойных кавычек ( §2.4.5 ):
Если виден только один экранирующий символ , один escape-символ отбрасывается, следующий символ накапливается, и накопление продолжается.
Это означает, что:
"\[([a-zA-Z0-9_-]+)]"
анализируется так же, как показано ниже, где backsla sh отсутствует:
"[([a-zA-Z0-9_-]+)]"
PCRE синтаксис, реализованный CL-PPCRE, понимает открывающую квадратную скобку как специальный синтаксис для классов символов и заканчивается следующей закрывающей скобкой. Таким образом, вышеприведенный код выглядит следующим образом:
[([a-zA-Z0-9_-]
Соответствующее дерево регулярных выражений:
CL-USER> (ppcre:parse-string "[([a-zA-Z0-9_-]")
(:CHAR-CLASS #\( #\[ (:RANGE #\a #\z) (:RANGE #\A #\Z) (:RANGE #\0 #\9) #\_ #\-)
Обратите внимание, в частности, что открывающая скобка внутри него обрабатывается буквально. Когда синтаксический анализатор встречает закрывающую скобку, которая следует за вышеупомянутым фрагментом, он интерпретирует его как конец группы регистров, но такая группа не была запущена, поэтому сообщение об ошибке в позиции 16 строки.
Чтобы избежать рассматривая скобку как класс символов, ей должна предшествовать буквальная обратная косая черта sh в строке, как вы пытались это сделать, но для этого необходимо записать два обратных знака sh символов :
CL-USER> (ppcre:parse-string "\\[([a-zA-Z0-9_-]+)]")
(:SEQUENCE #\[
(:REGISTER
(:GREEDY-REPETITION 1 NIL
(:CHAR-CLASS (:RANGE #\a #\z) (:RANGE #\A #\Z) (:RANGE #\0 #\9) #\_ #\-)))
#\])
Закрывающие квадратные скобки не нуждаются в обратном символе sh.
Я рекомендую вам писать регулярные выражения на Лиспе, используя древовидную форму, с терминами :regex
, когда это улучшает ясность : он избегает необходимости иметь дело с проблемами, которые приносит побег. Например:
CL-USER> (ppcre:scan-to-strings
'(:sequence "[" (:register (:regex "[a-zA-Z0-9_-]+")) "]")
"[has-instance]")
"[has-instance]"
#("has-instance")