2010-05-21 5 views
11

En Python, vous pourriez faire quelque chose commeTraitement par lots idiomatique de texte dans Emacs?

fout = open('out','w') 
fin = open('in') 
for line in fin: 
    fout.write(process(line)+"\n") 
fin.close() 
fout.close() 

(je pense que ce serait semblable dans de nombreuses autres langues). Dans Emacs Lisp, voulez-vous faire quelque chose comme

(find-file 'out') 
(setq fout (current-buffer) 
(find-file 'in') 
(setq fin (current-buffer) 
(while moreLines 
(setq begin (point)) 
(move-end-of-line 1) 
(setq line (buffer-substring-no-properties begin (point)) 
;; maybe 
(print (process line) fout) 
;; or 
(save-excursion 
    (set-buffer fout) 
    (insert (process line))) 
(setq moreLines (= 0 (forward-line 1)))) 
(kill-buffer fin) 
(kill-buffer fout) 

que je me suis inspiré (et code) de Emacs Lisp: Process a File line-by-line. Ou devrais-je essayer quelque chose de complètement différent? Et comment supprimer le "" de la déclaration d'impression?

Répondre

30

Si vous voulez réellement le traitement par lots de stdin et d'envoyer le résultat à stdout, vous pouvez utiliser l'option de ligne de commande --script à Emacs, qui vous permettra d'écrire du code qui lit à partir de stdin et écrit à stdout et stderr.

Voici un exemple de programme qui est comme cat, sauf qu'il renverse chaque ligne:

#!/usr/local/bin/emacs --script 
;;-*- mode: emacs-lisp;-*- 

(defun process (string) 
    "just reverse the string" 
    (concat (nreverse (string-to-list string)))) 

(condition-case nil 
    (let (line) 
     ;; commented out b/c not relevant for `cat`, but potentially useful 
     ;; (princ "argv is ") 
     ;; (princ argv) 
     ;; (princ "\n") 
     ;; (princ "command-line-args is") 
     ;; (princ command-line-args) 
     ;; (princ "\n") 

     (while (setq line (read-from-minibuffer "")) 
     (princ (process line)) 
     (princ "\n"))) 
    (error nil)) 

Maintenant, si vous aviez un fichier nommé stuff.txt qui contenait

abcd 
1234 
xyz 

Et vous invoquaient la script shell écrit ci-dessus comme si (en supposant qu'il est nommé rcat):

rcat < stuff.txt 

vous verrez ce qui suit imprimé à stdout:

dcba 
4321 
zyx 

Ainsi, contrairement à la croyance populaire, vous pouvez réellement faire le traitement des fichiers par lots sur stdin et n'ont pas fait de lire le fichier entier dans à la fois.

+0

... Fantastique ... – hatmatrix

+4

Référence croisée à la réponse suivante qui montre comment transmettre des arguments de ligne de commande supplémentaires aux scripts Emacs: http://stackoverflow.com/questions/6238331/emacs-shell-scripts-how- to-put-initial-options-dans-le-script # 6259330 – phils

5

Voici ce que j'ai trouvé. Me semble beaucoup plus idiomatique à moi:

(with-temp-buffer 
    (let ((dest-buffer (current-buffer))) 
    (with-temp-buffer 
     (insert-file-contents "/path/to/source/file") 
     (while (search-forward-regexp ".*\n\\|.+" nil t) 
     (let ((line (match-string 0))) 
      (with-current-buffer dest-buffer 
      (insert (process line))))))) 
    (write-file "/path/to/dest/file" nil)) 
1

Emacs Lisp ne convient pas pour le traitement des flux de fichiers. Le fichier entier doit être lu à la fois:

(defun my-line-fun (line) 
    (concat "prefix: " line)) 

(let* ((in-file "in") 
     (out-file "out") 
     (lines (with-temp-buffer 
     (insert-file-contents in-file) 
     (split-string (buffer-string) "\n\r?")))) 
    (with-temp-file out-file 
    (mapconcat 'my-line-fun lines "\n"))) 
+1

'split-string' sans arguments par défaut pour séparer sur' split-string-default-separators', qui est '" [\ f \ t \ n \ r \ v] + "' par défaut. Vous voulez probablement passer '" [\ n \ r] + "' explicitement comme deuxième argument. – haxney

+1

Et techniquement, "Emacs Lisp ne convient pas au traitement des flux de fichiers" n'est pas vrai; vous pouvez utiliser un filtre de processus, mais c'est beaucoup plus compliqué et lire le fichier entier en même temps est probablement le moyen le plus facile de faire les choses. Si la lecture d'un flux (comme une socket réseau) est vraiment nécessaire, vous devrez probablement utiliser un filtre de processus (voir le manuel Elisp). – haxney

+0

Merci: utilisation de split-string fixe. –

Questions connexes