如何用lisp替换文件中的字符串?

时间:2012-08-31 06:01:28

标签: lisp replace

替换文件中字符串的lisp方法是什么。

*file-path*标识的文件,搜索字符串*search-term*和替换字符串*replace-term*

如何将所有*search-term*个实例的文件替换为*replace-term*,最好代替旧文件?

3 个答案:

答案 0 :(得分:2)

还有一个问题,但很少有警告:

  1. 为了使其在现实生活中非常强大和可用,您需要将其包装到handler-case并处理各种错误,例如磁盘空间不足,设备未准备好,读取权限不足/写入,没有足够的内存来分配缓冲区等等。

  2. 这不做正则表达式替换,它是简单的字符串替换。对大文件进行基于正则表达式的替换可能看起来远不如从一开始就看起来那么简单,值得编写一个单独的程序,如sed或awk或整个语言,如Perl或awk;)

  3. 与其他解决方案不同,它会在要替换的文件附近创建一个临时文件,并将目前处理的数据保存到此文件中。这可能会更糟糕,因为它将使用更多的磁盘空间,但这更安全,因为如果程序在中间失败,原始文件将保持完整,不止于此,您可以稍后再继续更换例如,如果您将偏移量保存到临时文件中的原始文件中,则为临时文件。


  4. (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 :(得分: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

另请注意,此功能会将搜索字词替换为任何字符,包括换行符。

答案 2 :(得分: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)))

编辑:在上面的示例中,缓冲输入不允许正则表达式跨越 很多行 为了解决这个问题,这是一个更简单的实现,它将整个文件扫描为一个字符串:

(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)))
相关问题