LINUX.ORG.RU

>Чтобы можно было писать (E|e)macs вместо \(E\|e\)macs или даже \\(E\\|e\\)macs

Можно написать макрос, который преобразует строчку с твоим regex в строчку с каноническим видом regex Emacs. В коде ты напишешь

(looking-at (extended-regex-macro "(E|e)macs")...

А макрос extended-regex-macro у тебя развернется в «\\(E\\|e\\)macs».

Только зачем это? Разве экранирование скобок — это такая headache?

Еще есть пара хелперов, которые могут преобразовывать в регулярки строчки. Это regexp-opt, regexp-quote (см. Emacs Lisp Reference Manual). Эти конструкции можно использовать внутри eval-when-compile.

Zubok ★★★★★ ()
Ответ на: комментарий от annoynimous

>GNU emacs использует _extended_ regexp, судя по использованию именованных классов типа [:digit:]

Скорее basic regexp, поскольку имеет ссылки \1 .. \9. Остальное - нестандартные расширения (заимствования из extended).

ipc ()
Ответ на: комментарий от ipc

Ну можно и так сказать, хотя есть квантификаторы {n,m}, '+' является метасимволом и т.д.

Мне, честно говоря, не нравится деление регэкспов на basic/extended, тем более, что поддержка обратных ссылок связана с механизмом самих регулярных выражений (НКА/ДКА)

annoynimous ★★★★★ ()
Ответ на: комментарий от Zubok

Только зачем это? Разве экранирование скобок — это такая headache?

Читаемость портит изрядно, тем не менее (придется привыкать, чтобы зря не растить .emacs). На правах _фантазии_ (или страшный сон elisp'ера):

\\(defun regexp-opt-depth \\(regexp\\)
  "Return the depth of REGEXP.
This means the number of non-shy regexp grouping constructs
\\\(parenthesized expressions\\) in REGEXP."
  \\(save-match-data
    ;; Hack to signal an error if REGEXP does not have balanced parentheses.
    \\(string-match regexp ""\\)
    ;; Count the number of open parentheses in REGEXP.
    \\(let \\(\\(count 0\\) start last\\)
      \\(while \\(string-match "\\\\\\(\\\\(\\?:\\\\)?" regexp start\\)
	\\(setq start \\(match-end 0\\)\\)	      ; Start of next search.
	\\(when \\(and \\(not \\(match-beginning 1\\)\\)
		   \\(subregexp-context-p regexp \\(match-beginning 0\\) last\\)\\)
	  ;; It's not a shy group and it's not inside brackets or after
	  ;; a backslash: it's really a group-open marker.
	  \\(setq last start\\)	    ; Speed up next regexp-opt-re-context-p.
	  \\(setq count \\(1+ count\\)\\)\\)\\)
      count\\)\\)\\)

ipc ()
Ответ на: комментарий от ipc

Читаемость портит изрядно, тем не менее (придется привыкать, чтобы зря не растить .emacs). На правах _фантазии_ (или страшный сон elisp'ера):

Или макрос писать.

Примерно, я думаю, ты понимаешь. Просто абсолютно тупой пример, чтобы ты принцип понял. Но надо макрос для общего случая раскрутить:

(defmacro regexp-macro (str)
  (replace-regexp-in-string "\\([(|)]\\)" "\\\\\\1" str))

(defun foo (str)
  (re-search-forward (regexp-macro "(E|e)macs")))

Делаем M-x disassemble

byte code for foo:
  args: (str)
0	constant  re-search-forward
1	constant  "\\(E\\|e\\)macs"
2	call	  1
3	return	 
Zubok ★★★★★ ()
Ответ на: комментарий от Zubok

Даже так лучше. Тогда сам макрос в байт-код не попадет.

(eval-when-compile
  (defmacro regexp-macro (str)
    (replace-regexp-in-string "\\([(|)]\\)" "\\\\\\1" str)))
Zubok ★★★★★ ()
Ответ на: комментарий от ipc

>Чем это хуже?

Хуже чего? Ты еще разик прочитай. Тебе этот макрос, если и нужен, то только для переписывания своего кода. Возникает две ситуации:

1. Если мы не используем eval-when-compile, то при компиляции в *.elc макрос попадет в компилированный файл наравне с функциями, которые он переписал. Сразу вопрос, а зачем он тебе там? Ты его создал, чтобы только переписать программу нужным образом, а при работе программы и пользователю он не нужен.

2. Если мы используем eval-when-compile, то в компилированный файл макрос не попадает. Он же свою работ сделал — переписал регулярку нужным образом, регулярка подставилась во все места, переписанные функции скомпилировались. Это особенно удобно, если у тебя есть модуль my-macro с разухабистым макросом, который переписывает программу, гененрируя некоторую целевую. Тогда если ты напишешь (eval-when-compile (require 'my-macro)), то у тебя этот модуль с макросом заeval'уируется в момент компиляции, код перепишется в целевой, скомпилируется. При загрузке *.elc сам макрос уже не будет загружен.

Zubok ★★★★★ ()
Ответ на: комментарий от ipc

Смотря какую область он должен охватывать. Если тебе макрос нужен как system wide (то есть и в настройке Emacs, и в своих программах), то кидай его в ~/.emacs. Можно тогда и без eval-when-compile. А можешь свои макросы переписывающие вообще убрать в какой-нибудь модудь типа my-macros и подключать его, как показано выше.

     This form marks BODY to be evaluated at compile time but not when
     the compiled program is loaded.  The result of evaluation by the
     compiler becomes a constant which appears in the compiled program.
     If you load the source file, rather than compiling it, BODY is
     evaluated normally.

     If you have a constant that needs some calculation to produce,
     `eval-when-compile' can do that at compile-time.  For example,

          (defvar my-regexp
            (eval-when-compile (regexp-opt '("aaa" "aba" "abb"))))

     If you're using another package, but only need macros from it (the
     byte compiler will expand those), then `eval-when-compile' can be
     used to load it for compiling, but not executing.  For example,

          (eval-when-compile
            (require 'my-macro-package))  ;; only macros needed from this
Zubok ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.