2012-08-31 61 views
2

替換文件中字符串的lisp方式是什麼?如何用lisp替換文件中的字符串?

存在由*file-path*標識的文件,搜索字符串*search-term*和替換字符串*replace-term*

如何使文件*search-term*的所有實例替換爲*replace-term* s,最好代替舊文件?

回答

2

還有一個拿這個問題,但一些警告:

  1. 爲了使這個真強大和可用在真實的情況下,你將需要將其包裝到handler-case並處理各種錯誤,如磁盤空間不足,設備未準備好,讀/寫權限不足,內存不足以分配給緩衝區等等。

  2. 這不會做正則表達式替換,它是簡單的字符串替換。對大文件進行基於正則表達式的替換可能看起來不像從一開始就微不足道,值得編寫一個單獨的程序,像sed或awk或整個語言,比如Perl或awk;)

  3. 與其他解決方案不同,它將在要替換的文件附近創建一個臨時文件,並將迄今處理的數據保存到此文件中。這可能會更糟糕,因爲它會使用更多的磁盤空間,但這樣更安全,因爲如果程序在中間失敗,原始文件將保持不變,而不僅僅是這些,您可以稍後再繼續從中取代例如,如果您將臨時文件的偏移量保存到臨時文件中的原始文件中,則爲臨時文件。


(defun file-replace-string (search-for replace-with file 
          &key (element-type 'base-char) 
           (temp-suffix ".tmp")) 
    (with-open-file (open-stream 
        file 
        :direction :input 
        :if-exists :supersede 
        :element-type element-type) 
    (with-open-file (temp-stream 
        (concatenate 'string file temp-suffix) 
        :direction :output 
        :element-type element-type) 
     (do ((buffer (make-string (length search-for))) 
      (buffer-fill-pointer 0) 
      (next-matching-char (aref search-for 0)) 
      (in-char (read-char open-stream nil :eof) 
        (read-char open-stream nil :eof))) 
      ((eql in-char :eof) 
      (when (/= 0 buffer-fill-pointer) 
      (dotimes (i buffer-fill-pointer) 
       (write-char (aref buffer i) temp-stream)))) 
     (if (char= in-char next-matching-char) 
      (progn 
       (setf (aref buffer buffer-fill-pointer) in-char 
        buffer-fill-pointer (1+ buffer-fill-pointer)) 
       (when (= buffer-fill-pointer (length search-for)) 
       (dotimes (i (length replace-with)) 
        (write-char (aref replace-with i) temp-stream)) 
       (setf buffer-fill-pointer 0))) 
      (progn 
       (dotimes (i buffer-fill-pointer) 
       (write-char (aref buffer i) temp-stream)) 
       (write-char in-char temp-stream) 
       (setf buffer-fill-pointer 0))) 
     (setf next-matching-char (aref search-for buffer-fill-pointer))))) 
    (delete-file file) 
    (rename-file (concatenate 'string file temp-suffix) file)) 
1

它可以用很多方式完成,例如用正則表達式。最自足的方式,我看到的是類似如下:

(defun replace-in-file (search-term file-path replace-term) 
    (let ((contents (rutil:read-file file-path))) 
    (with-open-file (out file-path :direction :output :if-exists :supersede) 
     (do* ((start 0 (+ pos (length search-term))) 
      (pos (search search-term contents) 
       (search search-term contents :start2 start))) 
      ((null pos) (write-string (subseq contents start) out)) 
     (format out "~A~A" (subseq contents start pos) replace-term)))) 
    (values)) 

rutil:read-file這裏實現:https://github.com/vseloved/rutils/blob/master/core/string.lisp#L33

還要注意,此功能將取代搜索字詞與任何字符,包括換行。

0

與ireggex蛋雞方案:

(use irregex) ; irregex, the regular expression library, is one of the 
       ; libraries included with CHICKEN. 

(define (process-line line re rplc) 
    (irregex-replace/all re line rplc)) 

(define (quickrep re rplc) 
    (let ((line (read-line))) 
    (if (not (eof-object? line)) 
     (begin 
      (display (process-line line re rplc)) 
      (newline) 
      (quickrep re rplc))))) 

(define (main args) 
    (quickrep (irregex (car args)) (cadr args))) 

編輯:在上面的例子中緩衝所輸入的不允許的regexp可以跨越 許多行。
爲了對付這裏是一個更簡單的實現其掃描整個文件作爲一個字符串:第一

(use ireggex) 
(use utils) 

(define (process-line line re rplc) 
    (irregex-replace/all re line rplc)) 

(define (quickrep re rplc file) 
    (let ((line (read-all file))) 
     (display (process-line line re rplc)))) 

(define (main args) 
    (quickrep (irregex (car args)) (cadr args) (caddr args))) 
+0

我編輯它能夠。 – ramrunner