2012-10-24 9 views
5

Ho un elenco di stringhe che ho bisogno di formattare utilizzando emacs lisp. Questo era l'unico modo in cui potevo pensarci:Come formattare un elenco di stringhe

(setq slist '("is there" "any" "way" "directed iteration"))  
(format "%s _%s_ %s to do %S in elisp?" 
     (elt slist 0) 
     (elt slist 1) 
     (elt slist 2) 
     (elt slist 3) 
     (elt slist 4)) 

Dandomi quello che voglio.

is there _any_ way to do "directed iteration" in elisp? 

Ci deve essere un modo più elegante, ma dopo tanto pensare, non lo vedo. Sono molto nuovo a emacs lisp e potrei mancare qualcosa di ovvio.

risposta

4

Uso apply:

(apply 'format "%s _%s_ %s to do %S in elisp?" slist) 

La funzione apply prende una funzione (o simbolo) come primo parametro, allora un numero di singoli argomenti, terminando con una lista di argomenti.

+0

Sì, è esattamente, grazie. Era ovvio e mi mancava la natura di applicare. E wow, che grande funzione è! –

2

Ho deciso di trasformarlo in un progetto autonomo aggiungendo alcune funzionalità, correggendo alcuni bug e aggiungendo altri bug! yey :)

Potete trovare il progetto qui: http://code.google.com/p/formatting-el/source/browse/trunk/formatting.el

Non sono sicuro di come buggy molto questo è, ma a prima vista sembra funzionare:

(defun directive-end (c) 
    (member c "csdoxXeg%")) 

(defun pp-if-nil (spec) 
    (position ?\% spec)) 

(defun pp-list (spec args) 
    (let ((pos 0) (last 0) (fstring "% ") current seen-^) 
    (catch 't 
     (while t 
     (setq pos (1+ (or (position ?% spec :start pos) -1)) 
       current (aref spec pos)) 
     (unless (and seen-^ (char-equal current ?\}) (null args)) 
      (princ (substring spec last (1- pos)))) 
     (setq last pos pos (1+ pos)) 
     (cond 
     ((char-equal current ?^) 
      (incf last) 
      (setq seen-^ t)) 
     ((char-equal current ?\{) 
      (setq pos (+ pos (pp-list (substring spec pos) (car args))) 
       args (cdr args) 
       last pos 
       seen-^ nil)) 
     ((char-equal current ?\}) 
      (if args (setq pos 0 last 0) 
      (throw 't nil))) 
     ((char-equal current ?%) 
      (setq seen-^ nil last (1+ last)) 
      (write-char ?%)) 
     (t (unless args (error "Not enough argumens for list iteration")) 
      (setf (aref fstring 1) current) 
      (princ (format fstring (car args))) 
      (setq args (cdr args) 
        seen-^ nil 
        last 
        (or (position-if #'directive-end spec :start pos) 
         pos)))))) pos)) 

(defun cl-format (spec &rest args) 
    (with-output-to-string 
    (let ((pos 0) (last 0) (fstring "% ") current) 
     (catch 't 
     (while t 
      (setq pos (1+ (or (position ?\% spec :start pos) -1)) 
       current (aref spec pos)) 
      (when (= pos 0) (throw 't nil)) 
      (princ (substring spec last (1- pos))) 
      (setq last pos pos (1+ pos)) 
      (cond 
      ((char-equal current ?^) 
      (unless args 
       (setq last (pp-if-nil spec) 
        pos last))) 
      ((char-equal current ?\{) 
      (setq pos (+ pos (pp-list (substring spec pos) (car args))) 
        args (cdr args) 
        last pos)) 
      ((char-equal current ?\}) 
      (error "Unmatched list iteration termination directive")) 
      ((char-equal current ?%) 
      (write-char ?%) 
      (incf last)) 
      (t (unless args (error "Not enough argumens")) 
       (setf (aref fstring 1) current) 
       (princ (format fstring (car args))) 
       (setq args (cdr args) 
        last 
        (or (position-if #'directive-end spec :start pos) 
         pos)))) 
      (incf pos)))))) 

(cl-format "begin: %{%s = %d%^,%}; %% %c %% %{%{%s -> %d%^.%},%}" 
      '(a 1 b 2 c 3) ?\X '((a 2 b 4 c 6) (a 1 b 3 c 5))) 
"begin: a = 1,b = 2,c = 3; % X % a -> 2.b -> 4.c -> 6,a -> 1.b -> 3.c -> 5," 

Questo tenta di replicare alcuni (molto semplicistico) Comportamento di stampa simile a Lisp comune delle direttive ~{ ... ~}.