ack regex: Соответствие двух слов по порядку в одной строке

Мне нравятся макросы.

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

Некоторые люди смущены по поводу воображаемого штрафа во время выполнения макросов, таким образом, я добавил попытку разъяснения вещей в конце.

В Начале, Было Дублирование

(defun ldap-users ()
  (let ((people (make-hash-table :test 'equal)))
    (ldap:dosearch (ent (ldap:search *ldap* "(&(telephonenumber=*) (cn=*))"))
                   (let ((mail  (car (ldap:attr-value ent 'mail)))
                         (uid   (car (ldap:attr-value ent 'uid)))
                         (name  (car (ldap:attr-value ent 'cn)))
                         (phonenumber (car (ldap:attr-value ent 'telephonenumber))))
                      (setf (gethash uid people)
                            (list mail name phonenumber))))
    people))

, можно думать о "привязке, которой позволяют", как о локальной переменной, которая исчезает вне формы, которой ПОЗВОЛЯЮТ. Заметьте форму привязки - они очень похожи, отличаясь только по атрибуту объекта LDAP и имени ("локальная переменная") для привязки значения с. Полезный, но немного подробный и содержит дублирование.

На Quest для Красоты

Теперь, не было бы хорошо, если бы у нас не должно было быть всего того дублирования? Общая идиома, С-... макросы, которые связывают значения на основе выражения, от которого можно захватить значения. Давайте представим наш собственный макрос, который работает как этот, WITH-LDAP-ATTRS, и замените его в нашем исходном коде.

(defun ldap-users ()
  (let ((people (make-hash-table :test 'equal))) ; equal so strings compare equal!
    (ldap:dosearch (ent (ldap:search *ldap* "(&(telephonenumber=*) (cn=*))"))
                   (with-ldap-attrs (mail uid name phonenumber) ent
                       (setf (gethash uid people)
                             (list mail name phonenumber))))
    people))

Вы видели, как набор строк внезапно исчез и был заменен всего одной одной строкой? Как сделать это? Используя макросы, конечно - код, который пишет код! Макросы в Lisp являются полностью различным животным, чем те, можно найти в C/C++ с помощью препроцессора: здесь, можно работать реальный код Lisp (не #define пух в cpp), который генерирует код Lisp, прежде чем другой код будет скомпилирован. Макросы могут использовать любой реальный код Lisp, т.е. обычные функции. По существу никакие пределы.

Избавление от Ужасных

Так, давайте посмотрим, как это было сделано. Для замены одного атрибута мы определяем функцию.

(defun ldap-attr (entity attr)
  `(,attr (car (ldap:attr-value ,entity ',attr))))

синтаксис одинарной левой кавычки выглядит немного волосатым, но что он делает легко. При вызове LDAP-ATTRS он выложит список, который содержит значение из [1 111] (это - запятая), сопровождаемый [1 112] ("первый элемент в списке" (пара недостатков, на самом деле), и существует на самом деле функция, вызванная first, можно использовать, также), который получает первое значение в списке, возвращенном [1 114]. Поскольку это не код, который мы хотим выполнить, когда мы компилируем код (получение значений атрибута - то, что мы хотим сделать, когда мы работаем программа), мы не добавляем запятую перед вызовом.

Так или иначе. Прохождение, к остальной части макроса.

(defmacro with-ldap-attrs (attrs ent &rest body)
  `(let ,(loop for attr in attrs
         collecting `,(ldap-attr ent attr))
     ,@body)) 

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

Результат

можно легко проверить, что это даст Вам правильную вещь. Макросы часто пишутся этот путь: Вы начинаетесь с кодом, который Вы хотите сделать более простым (вывод), что Вы хотите записать вместо этого (вход), и затем Вы начинаете прессовать макрос, пока Ваш вход не дает корректный вывод. Функция macroexpand-1 скажет Вам, если Ваш макрос будет корректен:

(macroexpand-1 '(with-ldap-attrs (mail phonenumber) ent
                  (format t "~a with ~a" mail phonenumber)))

оценивает к [1 147]

(let ((mail (car (trivial-ldap:attr-value ent 'mail)))
      (phonenumber (car (trivial-ldap:attr-value ent 'phonenumber))))
  (format t "~a with ~a" mail phonenumber))

, Если Вы сравните ПОЗВОЛЕННУЮ привязку расширенного макроса с кодом в начале, Вы найдете, что это находится в той же форме!

Время компиляции по сравнению со Временем выполнения: Макросы по сравнению с Функциями

макрос А является кодом, который достигнут в [1 127] время компиляции с добавленным скручиванием, что они могут назвать любой обычным функция или макрос, как им нравится! Это не намного больше, чем необычный фильтр, беря некоторые аргументы, применяя некоторые преобразования и затем подавая компилятор получающийся s-экспорт

В основном, это позволяет Вам записать свой код в глаголах, которые могут быть найдены в проблемной области вместо примитивов низкого уровня с языка! Как глупый пример, рассмотрите следующее (если when уже не было встроенное)::

(defmacro my-when (test &rest body)
  `(if ,test 
     (progn ,@body)))

if встроенный примитив, который только позволит Вам выполниться один форма в ответвлениях, и если Вы хотите иметь больше чем один, ну, в общем, необходимо использовать progn::

;; one form
(if (numberp 1)
  (print "yay, a number"))

;; two forms
(if (numberp 1)
  (progn
    (assert-world-is-sane t)
    (print "phew!"))))

С нашим новым другом, my-when, мы могли оба a) использовать более соответствующий глагол, если у нас нет ложного ответвления и b) добавить неявный оператор упорядочивания, т.е. progn::

(my-when (numberp 1)
  (assert-world-is-sane t)
  (print "phew!"))

скомпилированный код никогда не будет содержать my-when, тем не менее, потому что в первой передаче, все макросы расширены, таким образом, существует никакой штраф во время выполнения включено!

Lisp> (macroexpand-1 '(my-when (numberp 1)
                        (print "yay!")))

(if (numberp 1)
  (progn (print "yay!")))

Примечание, что macroexpand-1 только делает один уровень расширений; это возможно (скорее всего, на самом деле!), который расширение продолжает далее вниз. Однако в конечном счете Вы поразите определенные для компилятора детали реализации, которые часто не очень интересны. Но продолжение расширения результата в конечном счете или получит Вас больше деталей, или просто Ваш вход s-exp назад.

Hope, которая разъясняет вещи. Макросы являются мощным инструментом и одной из функций в Lisp, который я люблю.

25
задан Amelio Vazquez-Reina 9 April 2011 в 20:59
поделиться

1 ответ

Вы хотите найти word_1, затем что угодно, любое количество раз, а затем word_2. Это должно быть

word_1.*word_2

Вы, кажется, используете *, поскольку он часто используется в поисках командной строки, но в регулярных выражениях это квантификатор для предыдущего символа, то есть соответствует ему по крайней мере 0 раз. Например, регулярное выражение a* будет соответствовать 0 или более a с, тогда как регулярное выражение a+ будет соответствовать по крайней мере одному a.

Метасимвол regex, означающий «соответствовать чему-либо», равен ., поэтому .* означает «соответствовать любому, любое количество раз. См. perlrequick для краткого введения в тему.

43
ответ дан 28 November 2019 в 21:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: