2015-07-19 48 views
3

我想写Python的正则表达式搜索的Common Lisp的版本和替换,以文件的就地修改:替换正则表达式,就地,与Common Lisp的

import fileinput, re 

for line in fileinput.input(inplace=1, backup='.bak'): 
    line = re.sub(r"foo", "bar", line, re.M) 
print (line) 

这是常见的Lisp代码我能想出来:

(require :cl-ppcre) 

(defun in-place-subst (file) 
    (with-open-file (stream file :direction :io :if-exists :overwrite) 
    (loop for line = (read-line stream nil) 
     while line do 
     (write-line (cl-ppcre:regex-replace-all "foo" line "bar") stream)))) 

它的工作,有点。现在替换文本将被添加到文件末尾。我眼前的问题是我无法弄清楚如何将替换成的内容。

为了更好的解释,如果file.txt包含:

1 foo 
2 bar 
3 foobar 

调用

(in-place-subst "file.txt") 

后,我得到:

1 foo 
2 bar 
3 foobar 
1 bar 
2 bar 
3 barbar 

取而代之的是正确的更换:

1 bar 
2 bar 
3 barbar 

我试图用一切可能的with-open-file选项(从Successful Lisp),没有成功:

Keyword  Value    Action if File Exists 
---------- ------------------ --------------------------------------- 
:IF-EXISTS NIL     return NIL 
:IF-EXISTS :ERROR    signal an error 
:IF-EXISTS :NEW-VERSION   next version (or error) 
:IF-EXISTS :RENAME    rename existing, create new 
:IF-EXISTS :SUPERSEDE   replace file upon CLOSE 
:IF-EXISTS :RENAME-AND-DELETE rename and delete existing, create new 
:IF-EXISTS :OVERWRITE   reuse existing file (position at start) 
:IF-EXISTS :APPEND    reuse existing file (position at end) 

可能有人请给我在正确的方向,使该功能将在正确的方式呈现file.txt

另外,什么是常见Lisp 惯用这样做的方式,当然假设cl-ppcre可用?

是否有更简洁的方式使用Common Lisp进行就地正则表达式替换?

+1

'FILE-POSITION'读取并设置文件位置。你可能想试验一下。 –

+0

谢谢您的建议。我尝试过使用'(文件位置流:启动)',尝试重置流的文件位置,没有太多进展。我相信可以用更多的代码来做到这一点(也许在内存中做一个副本,做替换和写回),但是我希望找到一个更简洁,也许更习惯的方式。 – gsl

+0

保存文件位置。阅读该行。将文件位置重置为开头。写新的一行。请注意,它不会更改行的大小或扩展文件。如果你的更换时间更短或更长,那么你需要处理... –

回答

8

在Python中,没有原始操作可以修改文件“in-place”; 有帮助程序类fileinput的功能,它给出了 通过首先将文件复制到备份文件来修改文件的错觉,然后 读取备份文件并将处理结果写入原来的一个。从manual

可选就地过滤:如果inplace=1传递 到fileinput.input()或到FileInput构造函数,则文件被移动 到备份文件和标准输出关键字参数被引导到输入文件 (如果一个与备份文件同名的文件已经存在,则该文件将被无提示地替换) 。 这使得可以编写一个过滤器来重写其输入文件。 如果给出备份参数(通常为backup ='。'),则它指定备份文件的扩展名,备份文件保留为 ;默认情况下,扩展名是'.bak',并且在输出 文件关闭时删除。当读取标准输入时,就地过滤被禁用。

所以,做Common Lisp中这种操作的方式是模仿 Python code,先用这个functionmy-copy-file将文件复制到备份文件,例如,然后写了下面的代码:

(defun in-place-subst (file) 
    (let ((backup-file (concatenate 'string file ".bak"))) 
    (my-copy-file file backup-file) 
    (with-open-file (in-stream backup-file) 
     (with-open-file (out-stream file :direction :output :if-exists :supersede) 
     (loop for line = (read-line in-stream nil) 
      while line do 
      (write-line (cl-ppcre:regex-replace-all "foo" line "bar") out-stream)))))) 
+0

谢谢你的信息和漂亮的代码! – gsl