Подтвердить что ты не робот

Идиоматическая пакетная обработка текста в Emacs?

В 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: последовательно обрабатывать файл. Или я должен попробовать что-то совершенно другое? И как удалить "" из инструкции печати?

4b9b3361

Ответ 1

Если вам действительно нужна пакетная обработка 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

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

rcat < stuff.txt

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

dcba
4321
zyx

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

Ответ 2

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

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

Ответ 3

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