Идиоматическая пакетная обработка текста в Emacs? - PullRequest
11 голосов
/ 21 мая 2010

В Python вы можете сделать что-то вроде

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

(я думаю, что это будет похоже и на многие другие языки). В Emacs Lisp, вы бы сделали что-то вроде

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

, который я получил (и код) от Emacs Lisp: построчная обработка файла Или я должен попробовать что-то совершенно другое? А как убрать "" из оператора print?

Ответы [ 3 ]

33 голосов
/ 25 мая 2010

Если вы действительно хотите пакетную обработку stdin и отправку результата в stdout, вы можете использовать опцию командной строки - script для Emacs, которая позволит вам писать код, который читает из stdin и пишет в stdout и stderr.

Вот пример программы, которая похожа на cat, за исключением того, что она переворачивает каждую строку:

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

Теперь, если у вас есть файл с именем stuff.txt, который содержит

abcd
1234
xyz

И вы вызвали скрипт оболочки, написанный выше, примерно так (при условии, что он называется rcat):

rcat < stuff.txt

вы увидите следующее, напечатанное на стандартный вывод:

dcba
4321
zyx

Таким образом, вопреки распространенному мнению, вы можете на самом деле выполнять пакетную обработку файлов на stdin, и на самом деле вам не нужно читать весь файл сразу.

5 голосов
/ 21 мая 2010

Вот что я придумал. Выглядит гораздо более идиоматично для меня:

(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 голос
/ 21 мая 2010

Emacs Lisp не подходит для обработки файловых потоков. Весь файл должен быть прочитан сразу:

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