如何迭代文件和替换文本

时间:2011-02-07 09:26:40

标签: python python-2.6

我是python初学者:如何在一个目录中迭代csv文件并替换字符串,例如

ww into vv
.. into --

所以,我不想将拥有ww的行替换为vv,只需将这行中的字符串替换为vv。我试过像

这样的东西
#!/Python26/
# -*- coding: utf-8 -*-

import os, sys
for f in os.listdir(path):
    lines = f.readlines() 

但是如何继续?

3 个答案:

答案 0 :(得分:8)

import os
import csv

for filename in os.listdir(path):
    with open(os.path.join(path, filename), 'r') as f:
        for row in csv.reader(f):
            cells = [ cell.replace('www', 'vvv').replace('..', '--')
                      for cell in row ]
            # now you have a list of cells within one row
            # with all strings modified.

编辑:您是学习/练习Python还是只需要完成工作?在后一种情况下,请使用sed程序:

sed -i 's/www/vvv/g' yourPath/*csv
sed -i 's/\.\./,,/g' yourPath/*csv

答案 1 :(得分:1)

如果你想用相同长度的字符串替换字符串,可以在适当的位置替换,也就是说只重写必须替换的位,而不必记录新修改的整个文件。

因此,使用正则表达式,这很容易做到。该文件是CSV文件的事实在此方法中绝对没有重要性:

from os import listdir
from os.path import join
import re
pat = re.compile('ww|\.\.')
dicrepl = {'ww':'vv' , '..':'--'}

for filename in listdir(path):
    with open(join(path,filename),'rb+') as f:
        ch = f.read()
        f.seek(0,0)
        pos = 0
        for match in pat.finditer(ch):
            f.seek(match.start()-pos, 1)
            f.write(dicrepl[match.group()])
            pos = match.end()

绝对有必要以二进制模式打开进行此类处理:它是模式'rb +'中的'b'。

文件以'r +'模式打开的事实允许在其中的任何所需位置读取和写入(如果它在'a'中打开,我们只能在文件的末尾写入)

但是如果文件太大而 ch 对象占用的内存太多,则应该修改它。

如果替换的长度与原始字符串的长度不同,则必须使用所做的修改来记录新文件。 (如果替换字符串的长度总是小于替换字符串的长度,则是特殊情况,并且仍然可以在不必记录新文件的情况下进行处理。在大文件上可能很有趣)

f.seek(match.start() - pos,1)而不是 f.seek(match.start(),0)的兴趣是它将指针从位置 pos 移动到位置 match.start(),而不必将指针从位置 0 移动到 match.start()然后每次从 0 match.start()

相反,使用 f.seek(match.start(),0)时,必须首先将指针移回位置 0 (文件的开头)然后向上移动,同时计算 match.start()字符数,使其停在正确的位置 match.start(),因为寻求(... ,0)表示从文件的开头获得位置,而 seek(...,1)表示从CURRENT位置进行移动。 编辑:

如果你想只更换隔离的'ww'字符串而不是更长字符串'wwwwwww'中的'ww'字符串,那么正则表达式必须是

pat = re.compile('(?<!w)ww(?!w)|(?<!\.)\.\.(?!\.)')

正则表达式可以通过 replace()获得,而无需棘手的字符串操作。

编辑:

我在 f.read()之后忘记了 f.seek(0,0)指令。该指令是将文件指针移回文件开头所必需的,因为在读取过程中指针会一直移动到最后。

我已更正了代码,现在可以正常运行。

这是一个代码,用于跟踪正在处理的内容:

from os import listdir
from os.path import join
import re
pat = re.compile('(?<!w)ww(?!w)|(?<!\.)\.\.(?!\.)')
dicrepl = {'ww':'vv' , '..':'ZZ'}

path = ...................................

with open(path,'rb+') as f:
    print "file has just been opened, file's pointer is at position ",f.tell()
    print '- reading of the file : ch = f.read()'
    ch = f.read()
    print "file has just been read"+\
          "\nfile's pointer is now at position ",f.tell(),' , the end of the file'
    print "- file's pointer is moved back to the beginning of the file : f.seek(0,0)"
    f.seek(0,0)
    print "file's pointer is now again at position ",f.tell()
    pos = 0
    print '\n- process of replacrement is now launched :'
    for match in pat.finditer(ch):
        print
        print 'is at position ',f.tell()
        print 'group ',match.group(),' detected on span ',match.span()
        f.seek(match.start()-pos, 1)
        print 'pointer having been moved on position ',f.tell()
        f.write(dicrepl[match.group()])
        print 'detected group have been replaced with ',dicrepl[match.group()]
        print 'now at position ',f.tell()
        pos = match.end()

答案 2 :(得分:0)

有关替换字符串的信息,请参阅其他答案。我想添加有关迭代文件的更多信息,问题的第一部分。

如果要通过目录和所有子目录进行递归,请使用os.walk()os.listdir()不会递归,或在其生成的文件名中包含目录名称。使用os.path.join()形成更完整的路径名。