使用Python查找和替换问题

时间:2017-10-07 12:33:02

标签: python

我有一组带有;分隔符的.csv文件。我需要用空格替换数据中的某些垃圾值。示例问题行是:

103273;CAN D MAT;B.C.;B.C.;B.C.;03-Apr-2006

查找和替换后的所需行是:

103273;CAN D MAT;;;;03-Apr-2006

在上面的示例中,我将;B.C.;替换为;;

我不能只替换B.C.,因为我需要匹配此特定错误情况的整个单元格值。我正在使用的代码是:

import os, fnmatch

def findReplace(directory, filePattern):
        for path, dirs, files in os.walk(os.path.abspath(directory)):
            for filename in fnmatch.filter(files, filePattern):
                filepath = os.path.join(path, filename)
                with open(filepath) as f:
                    s = f.read()
                for [find, replace] in zip([';#DIV/0!;',';B.C.;'],[';;',';;']        
                    s = s.replace(find, replace)
                with open(filepath, "w") as f:
                    f.write(s)

findReplace(*Path*, "*.csv")

我得到的输出是:

103273;CAN D MAT;;B.C.;;03-Apr-2006

有人可以帮忙解决这个问题吗?

提前致谢!

2 个答案:

答案 0 :(得分:2)

[find, replacement]对不适合您的目的。 用;替换; +值+ ;;实际上只是一种复杂的方式,表示您要删除value列。

所以不要使用[find, replacement]对, 将;上的行拆分为字段会更自然,更直接, 用空字符串替换被认为是垃圾的值, 然后再次加入值:

JUNK = frozenset(['#DIV/0!', 'B.C.'])

def clean(s):
    return ';'.join(map(lambda x: '' if x in JUNK else x, s.split(';')))

您可以在实现中使用此功能(或将其内联复制):

def findReplace(directory, filePattern):
    for path, dirs, files in os.walk(os.path.abspath(directory)):
        for filename in fnmatch.filter(files, filePattern):
            filepath = os.path.join(path, filename)

            cleaned_lines = []
            with open(filepath) as f:
                for line in f.read():
                    cleaned_lines.append(clean(line))

            with open(filepath, "w") as f:
                f.write('\n'.join(cleaned_lines))

答案 1 :(得分:1)

str.replace,一旦进行了一次替换,就会在替换后的最后一个字符后继续扫描下一个字符。因此,当两个;B.C.;重叠时,它不会替换两者。

只有当B.C.出现在两个;之间时,您可以使用the re module替换>>> import re >>> s = "103273;CAN D MAT;B.C.;B.C.;B.C.;03-Apr-2006" >>> re.sub(r'(?<=;)B[.]C[.](?=;)', "", s) '103273;CAN D MAT;;;;03-Apr-2006' ,使用前瞻和后瞻断言:

;

...但在这种情况下,最好将行拆分为>>> fields = s.split(';') >>> for i, f in enumerate(fields): ... if f in ('B.C.', '#DIV/0!'): ... fields[i] = '' ... >>> ';'.join(fields) '103273;CAN D MAT;;;;03-Apr-2006' 上的字段,替换与要删除的字符串匹配的字段,然后再将字符串连接在一起。

;

这有两个主要优点:您不必为每个替换的字符串编写相当复杂的正则表达式;如果其中一个字段位于该行的开头或结尾,它仍然有效。

对于任何比此更复杂的CSV解析(例如,如果任何字段可以包含引用的$this->db->set('status','og'); $this->db->where('my_date_time < NOW()',false); $this->db->update('mytable'); 个字符,或者如果文件具有应跳过的标题),请查看csv module