2010-05-21 16 views
11

In Python, könnten Sie so etwas wieIdiomatische Stapelverarbeitung von Text in Emacs?

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

(Ich denke, es wäre ähnlich in vielen anderen Sprachen auch) tun. In Emacs Lisp, würden Sie tun so etwas wie

(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) 

, die ich Inspiration bekam (und Code) von Emacs Lisp: Process a File line-by-line. Oder sollte ich etwas ganz anderes ausprobieren? Und wie entfernt man die "" aus der print-Anweisung?

Antwort

30

Wenn Sie tatsächlich die Stapelverarbeitung von stdin wollen und das Ergebnis an stdout senden, können Sie die --script Befehlszeilenoption zu Emacs verwenden, die Sie Code zu schreiben, ermöglicht es, dass liest aus stdin und schreibt auf stdout und stderr. Hier

ist ein Beispielprogramm, das wie cat ist, mit der Ausnahme, dass es umgekehrt jede Zeile:

#!/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)) 

Nun, wenn Sie eine Datei haben stuff.txt benannt, die

enthielt
abcd 
1234 
xyz 

Und Sie berufen ich die Shell-Skript wie oben geschrieben (vorausgesetzt, es heißt rcat):

rcat < stuff.txt 

Sie werden sehen, die auf der Standardausgabe gedruckt folgenden:

dcba 
4321 
zyx 

Also, entgegen der landläufigen Meinung, die Sie tatsächlich tun Batch-Datei Verarbeitung auf stdin können und nicht tatsächlich auf einmal die gesamte Datei zu lesen.

+0

... Fantastisch ... – hatmatrix

+4

Querverweis auf die folgende Antwort, die zeigt, wie zusätzliche Befehlszeilenargumente an Emacs-Skripts übergeben werden: http://stackoverflow.com/questions/6238331/emacs-shell-scripts-how- to-put-initial-Optionen-ins-Skript # 6259330 – phils

5

Hier ist, was ich gefunden habe. Sieht mir viel idiomatischer zu mir:

(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 ist nicht geeignet für die Verarbeitung von Datei-Streams. Die gesamte Datei muss auf einmal gelesen werden:

(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' ohne Argumente führt standardmäßig zum Aufteilen auf' split-string-default-separators', das ist '" [\ f \ t \ n \ r \ v] + "' standardmäßig. Wahrscheinlich wollen Sie '' [\ n \ r] + "' explizit als zweites Argument übergeben. – haxney

+1

Und technisch, "Emacs Lisp ist nicht geeignet für die Verarbeitung von Datei-Streams" ist nicht wahr; Sie könnten einen Prozessfilter verwenden, aber es ist viel komplizierter und das Lesen der gesamten Datei auf einmal ist wahrscheinlich der einfachste Weg, um Dinge zu tun. Wenn das Lesen eines Streams (z. B. eines Netzwerk-Sockets) wirklich erforderlich ist, müssten Sie wahrscheinlich einen Prozessfilter verwenden (siehe Elisp-Handbuch). – haxney

+0

Danke: feste Split-String-Verwendung. –