Emacs Lisp: может ли одно и то же регулярное выражение соответствовать двум различным шаблонам с одинаковым количеством группировок? - PullRequest
7 голосов
/ 03 февраля 2012

Я начал писать сценарии Emacs в соответствии с указаниями, указанными в http://www.emacswiki.org/emacs/EmacsScripts,, которые в основном говорят, что ваши сценарии должны начинаться с:

:;exec emacs --script "$0" $@ 

Теперь я хотел бы настроить auto-mode-interpreter-regexp' accordingly, to make Emacs scripts automatically loaded withemacs-lisp-mode '.

Первоначальный `auto-mode-interpreter-regexp' должен был соответствовать:

#! /bin/bash
#! /usr/bin/env perl

и т. д., и, таким образом, это был тот1012 *

"\\(?:#![   ]?\\([^     \n]*/bin/env[   ]\\)?\\([^  \n]+\\)\\)"

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

(setq auto-mode-interpreter-regexp
   (concat ;; match "#! /bin/bash", "#! /usr/bin/env perl", etc.
           "\\(?:#![    ]?\\([^     \n]*/bin/env[   ]\\)?\\([^  \n]+\\)\\)"
           ;; or
           "\\|"
           ;; match ":;exec emacs "
           "\\(?::;[    ]?\\(exec\\)[   ]+\\([^     \n]+\\)[    ]*\\)"))

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

(setq auto-mode-interpreter-regexp
    (concat ;; match "#!" or ":;"
            "\\(?:#!\\|:;\\)"
            ;; optional spaces
            "[  ]?"
            ;; match "/bin/bash", "/usr/bin/env" or "exec" 
            "\\(\\[^    \n]*/bin/env[   ]\\|exec[   ]\\)?"
            ;; match interpreter
            "\\([^  \n]+\\)"))

Могли бы я сделать лучше?Спасибо.

Ответы [ 2 ]

1 голос
/ 03 февраля 2012

Regexp в Emacs поддерживает использование конструкции "явно пронумерованная группа" для назначения номера группы любому подспариванию.См. Руководство по Elisp 34.3.1.3 Конструкции с обратной косой чертой в регулярных выражениях .

Синтаксис ‘(?num: ... )’, где num - номер выбранной группы.

1 голос
/ 03 февраля 2012

Группировка регулярного выражения определяется круглыми скобками, которые в нем появляются. Вот почему второе из ваших трех регулярных выражений соответствует, но не может использоваться в этом случае: «exec» и «emacs» собираются в группах 3 и 4 соответственно, но auto-mode-interpreter-regexp ожидает, что имя интерпретатора сценария будет в группе 2.

(РЕДАКТИРОВАТЬ: То, что я написал выше, неверно, за исключением релевантности группы 2 для auto-mode-interpreter-regexp. См. Ответ huaiyuan для понимания.)

Из документации указанной переменной:

Соответствующие интерпретаторы Regexp для определения режима файла. это регулярное выражение сопоставляется с первой строкой файла определить режим файла в `set-auto-mode '. Если это соответствует, файл предполагается, что интерпретатор интерпретируется вторым группа регулярного выражения.

Думаю, ваше окончательное решение выглядит довольно хорошо. Два комментария:

  1. Исходное регулярное выражение заключено в \\(?:...\\). Это не влияет на совпадение как таковое, но если вы используете его в сочетании с другими регулярными выражениями, это может быть полезно в случаях, когда вы добавляете оператор постфикса:

    (setq my-regexp (concat auto-mode-interpreter-regexp "?"))

  2. Ваше регулярное выражение теперь также соответствует вещам типа #!exec..., что не может быть проблемой. Это происходит потому, что вы учли шебанг, что является правильным решением, так как (match-string 1) должен соответствовать (/usr)/bin/env или exec соответственно, без учета шебанга.

...