Исправление регулярного выражения "\[([a-zA-Z0-9_-]+)]"

Следующее регулярное выражение cl-ppcre вызывает ошибку:

(ppcre:scan-to-strings "\[([a-zA-Z0-9_-]+)]" "[has-instance]")

debugger invoked on a CL-PPCRE:PPCRE-SYNTAX-ERROR in thread
#<THREAD "main thread" RUNNING {10010B0523}>:
  Expected end of string. at position 16 in string "[([a-zA-Z0-9_-]+)]"

В качестве возвращаемых значений я ожидал:

“[has-instance]”
#(“has-instance”)

чтобы добраться до строки в скобках. Может ли кто-нибудь предоставить исправление регулярного выражения? Спасибо.

2 ответа

Решение

Управляющий символ (обратная косая черта) экранирует только сам себя и двойные кавычки ( §2.4.5 Двойные кавычки):

Если виден одиночный escape-символ, одиночный escape-символ отбрасывается, следующий символ накапливается, и накопление продолжается.

Что означает, что:

 "\[([a-zA-Z0-9_-]+)]" 

анализируется так же, как следующий, где нет обратной косой черты:

 "[([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 строки.

Чтобы не рассматривать скобку как класс символов, ей должна предшествовать буквальная обратная косая черта в строке, как вы пытались сделать, но для этого вы должны написать два символа обратной косой черты:

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) #\_ #\-)))
 #\])

В закрывающих квадратных скобках нет обратной косой черты.

Я рекомендую вам писать регулярные выражения на Лиспе, используя древовидную форму, с :regexтермины, когда он улучшает ясность: он позволяет избежать проблем, связанных с побегом. Например:

CL-USER> (ppcre:scan-to-strings 
           '(:sequence "[" (:register (:regex "[a-zA-Z0-9_-]+")) "]")
           "[has-instance]")
"[has-instance]"
#("has-instance")
  1. Двойной экранирование квадратных скобок.
  2. Вы также забыли (удвоить) экранировать закрывающую скобку.
(cl-ppcre:scan-to-strings "\\[([a-zA-Z0-9_-]+)\\]" "[has-instance]")
;; "[has-instance]" ;
;; #("has-instance")

Для тех, кто плохо знаком с обычным lisp, вы импортируете cl-ppcre используя quicklisp:

(load "~/quicklisp/setup.list") ;; adjust path to where you installed your quicklisp
(ql:quickload :cl-ppcre)
Другие вопросы по тегам