2017-10-07 108 views
0

我有一組帶有;分隔符的.csv文件。我需要用空白替換數據中的某些垃圾值。樣本問題行:使用Python查找和替換問題

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

可有人請這個問題的幫助?

在此先感謝!

+0

所以基本上你想用''(空字符串)替換'#DIV/0!'和'B.C.'。爲什麼不這樣做呢?用直接的方法。 – nutmeg64

+0

發佈的程序將給出''103273; CAN D MAT ;;;;;;;; 03-Apr-2006''作爲示例輸入,這與您寫的內容不同。 – janos

+0

@nutmeg:我也有短語B.C. (作爲單元格中字符串的一部分)。我只想替換整個單元格值與此匹配的位置。而且,這兩個值只是代表性的。我還有大約20個其他的值,比如「January」和「January」。 另外,我是新來的python所以不能確定你的意思是直接的方法。 –

回答

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)) 
+0

更正了錯字。 我不太瞭解它是如何工作的,但從我所瞭解的情況來看,該計劃正在撿起第一個和最後一個; B.C。作爲替換的字符串而忽略中間的字符串。 –

+0

@SagarJoshi哦,我明白了。我重寫了我的答案。 – janos

+0

@SagarJoshi你需要更多的幫助嗎? – janos

1

str.replace,一旦^ h作爲一個替代品,在最後一件物品被替換後繼續從下一個字符開始掃描。所以當兩個;B.C.;重疊時,它不會取代兩者。

您可以使用the re module更換B.C.僅當出現兩份;之間,利用先行和後向斷言:

>>> 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分析比這更復雜(例如,如果任何字段可以包含引用的;字符,或者如果文件具有應該跳過的標題),請查看csv module

+0

我會試試這個。我不太確定加入絃樂部分。數據有點混亂,它包含逗號和分號作爲單元值的一部分。 (該文件是csv,具有分號分隔符,但該字符串也包含這些字符) –

+0

@SagarJoshi如果引用文字分號,例如在數據中出現爲'a \; b'或'「a; b」',那麼你應該使用'csv'模塊來解析它。如果這不起作用,正則表達式可能是最好的選擇(儘管不一定像我在這裏所做的那樣)。 – trentcl

+0

(可能值得明確指出'csv'支持許多方言,比如'''''''''''限制和各種引用形式[方言](https://docs.python.org/2/library/csv.html #方言和格式化參數)) – trentcl