0

我是 Python 新手,我需要做一个解析练习。我有一个文件,我需要解析它(只是标题),但在处理之后,我需要保持文件相同的格式、相同的扩展名和磁盘中的相同位置,但只有不同之处新的标题..

我试过这个代码......

for line in open ('/home/name/db/str/dir/numbers/str.phy'):
    if line.startswith('ENS'):
        linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
        print linepars

..它完成了这项工作,但我不知道如何用新的解析“覆盖”文件。

4

5 回答 5

4

最简单但不是最有效的方法(到目前为止,尤其是对于长文件)是重写整个文件。

您可以通过打开第二个文件句柄并重写每一行来做到这一点,除了在标题的情况下,您将编写已解析的标题。例如,

fr = open('/home/name/db/str/dir/numbers/str.phy')
fw = open('/home/name/db/str/dir/numbers/str.phy.parsed', 'w') # Name this whatever makes sense

for line in fr:
    if line.startswith('ENS'):
        linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
        fw.write(linepars)
    else:
        fw.write(line)

fw.close()
fr.close()

编辑:请注意,这不使用readlines(),因此它的内存效率更高。它也不存储每个输出行,而是一次只存储一个,立即将其写入文件。

作为一个很酷的技巧,您可以使用with输入文件上的语句来避免关闭它(Python 2.5+):

fw = open('/home/name/db/str/dir/numbers/str.phy.parsed', 'w') # Name this whatever makes sense

with open('/home/name/db/str/dir/numbers/str.phy') as fr:
    for line in fr:
        if line.startswith('ENS'):
            linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
            fw.write(linepars)
        else:
             fw.write(line)

fw.close()

PS欢迎:-)

于 2011-05-19T17:57:06.937 回答
2

正如其他人在这里所说,您想打开一个文件并使用该文件对象的.write()方法。

最好的方法是打开一个附加文件进行写入:

import os

current_cfg = open(...)
parsed_cfg  = open(..., 'w')
for line in current_cfg:
    new_line = parse(line)
    print new_line
    parsed.cfg.write(new_line + '\n')
current_cfg.close()
parsed_cfg.close()

os.rename(....) # Rename old file to backup name
os.rename(....) # Rename new file into place

此外,我建议查看该tempfile模块并使用其中一种方法来命名您的新文件或打开/创建它。就我个人而言,我更倾向于将新文件与现有文件放在同一目录中,以确保它os.rename能够以原子方式工作(命名的配置文件将保证指向旧文件或新文件;在任何情况下它都不会指向部分写入/复制的文件)。

于 2011-05-19T18:03:23.383 回答
0

以下代码完成了这项工作。
我的意思是它确实会覆盖自己的文件;这就是OP所要求的。这是可能的,因为转换只是删除字符,所以写入的文件指针fo总是在读取的文件指针fi后面。

import re

regx = re.compile('\AENS([A-Z]+)0+([0-9]{6})')

with open('bomo.phy','rb+') as fi, open('bomo.phy','rb+') as fo:
    fo.writelines(regx.sub('\\1\\2',line) for line in fi)

我认为写入不是由操作系统一次一行执行,而是通过缓冲区执行。因此,在写入转换后的行池之前会读取几行。那就是我所想的。

于 2011-12-26T14:16:55.487 回答
-1
newlines = []
for line in open ('/home/name/db/str/dir/numbers/str.phy').readlines():
    if line.startswith('ENS'):
        linepars = re.sub ('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
        newlines.append( linepars )
open ('/home/name/db/str/dir/numbers/str.phy', 'w').write('\n'.join(newlines))
于 2011-05-19T17:54:31.660 回答
-1

(旁注:当然,如果您正在处理大文件,您应该知道所需的优化级别可能取决于您的情况。Python 本质上是非常不延迟评估的。如果您使用以下解决方案,则不是一个好的选择正在解析大文件,例如数据库转储或日志,但一些调整(例如嵌套with子句和使用惰性生成器或逐行算法)可以允许 O(1) 内存行为。)

targetFile = '/home/name/db/str/dir/numbers/str.phy'

def replaceIfHeader(line):
    if line.startswith('ENS'):
        return re.sub('ENS([A-Z]+)0+([0-9]{6})','\\1\\2',line)
    else:
        return line

with open(targetFile, 'r') as f:
    newText = '\n'.join(replaceIfHeader(line) for line in f)

try:
    # make backup of targetFile
    with open(targetFile, 'w') as f:
        f.write(newText)
except:
    # error encountered, do something to inform user where backup of targetFile is

编辑:感谢杰夫的建议

于 2011-05-19T18:07:56.293 回答