2012-02-02 2 views
7

Ho iniziato a scrivere sceneggiature di Emacs in base alle indicazioni fornite in http://www.emacswiki.org/emacs/EmacsScripts, che sostanzialmente dicono che gli script devono iniziare con:Emacs Lisp: la stessa espressione regolare può corrispondere a due modelli diversi con lo stesso numero di raggruppamenti?

:;exec emacs --script "$0" [email protected] 

Ora mi piacerebbe personalizzare auto-mode-interpreter-regexp' accordingly, to make Emacs scripts automatically loaded with emacs-lisp-mode'.

L'originale `auto-mode-interprete-regexp' stato destinato per abbinare:

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

e così via, e quindi era questo:

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

Ho provato ad aggiungere la nuova regexp come alternativa:

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

ma questo, mentre si abbina l'intera stringa, non è riuscito a catturare le sue submatches, esp ecialmente il secondo che è necessario per rilevare l'interprete. Così, ho mescolato l'espressione regolare per abbinare sia le intestazioni allo stesso tempo:

(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]+\\)")) 

avrei potuto fare meglio? Grazie.

risposta

1

I raggruppamenti di un'espressione regolare sono definiti dalle parentesi che appaiono in esso. Ecco perché la seconda delle tue tre espressioni regolari corrisponde ma non può essere utilizzata in questo caso: "exec" e "emacs" vengono catturati rispettivamente nei gruppi 3 e 4, ma auto-mode-interpreter-regexp si aspetta che il nome dell'interprete di script sia nel gruppo 2.

(EDIT: quello che ho scritto sopra è sbagliato, tranne che per la rilevanza del gruppo 2 per auto-mode-interpreter-regexp veda la risposta di Huaiyuan per approfondimenti..)

Dalla documentazione di tale variabile:

Regexp corrispondenza interpreti, per la determinazione della modalità file. Questa espressione regolare viene confrontata con la prima riga di un file su determinare la modalità del file in `set-auto-mode '. Se corrisponde, si presume che il file sia interpretato dall'interprete corrispondente al secondo gruppo dell'espressione regolare.

Penso che la soluzione finale sia piuttosto buona. Due commenti:

  1. L'espressione regolare originale è compresa tra \\(?:...\\). Questo non ha alcuna influenza sulla partita in sé, ma se lo si utilizza in combinazione con altre espressioni regolari può essere utile nei casi in cui si aggiunge un operatore postfix:

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

  2. Il tuo regexp ora corrisponde anche a cose come #!exec..., che potrebbe non essere un problema. Ciò si verifica perché hai scomposto lo shebang, che è la cosa giusta da fare come (match-string 1) corrisponde allo (/usr)/bin/env o allo exec rispettivamente, senza includere lo shebang.