2013-10-06 18 views
0

我試圖解析以下文件(從我的本地銀行交易出口):解析不均勻,但CSV上下的文本文件

Clnr Kontonr  Konto    Valuta Bokföringsdatum Transaktionsdatum Referens       Kontohändelse     Belopp 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   Hyresgästför      Autogiro      -15,00 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   SPOTIFY SPOTIFY      Kortköp/uttag     -19,00 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   +46123456789      Swish mottagen     80,00 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   PRIS NYCKELKUND      Debiteringsavgift    -49,00 
12345 1234567890 vardagskonto   SEK  13-09-27   13-09-27   12345678       direktbetalning    -301,00 
12345 1234567890 vardagskonto   SEK  13-09-27   13-09-27   Unionen        Bg-bet. via internet   -125,00 
12345 1234567890 vardagskonto   SEK  13-09-26   13-09-26   123456789Överföring     -1 000,00 

但我似乎無法建立一個適當的正則表達式它。我們的目標是提取第5,6,7和9列(如果所有這些都可以被提取出來,這當然是一種獎勵),但第7列是非常複雜的一個,因爲文件不是CSV,第7列可以包含多個詞。第8列是不可預測的,但我想我在上面的例子中找到了大多數相關的可能性。

關於如何成功解析此文件的任何提示?顯然我的正則表達式是不夠的。 :-(

如果這有什麼差別,我寧願它是否能在Python甚至POSIX(的grep/sed的/等)來解決或

+0

由於文件似乎具有固定的列寬度,您應該能夠通過將每行字符串與每列的起始位置和結束位置切片,從列中獲取各個值。 –

+0

爲什麼不爲每條線獲得固定寬度的子字符串?就像'line [48:57]'獲得第四列。 – Jerry

+0

你有沒有嘗試在'\ t'上分割它? 'import csv;打開('foo.txt')爲f:reader = csv.reader(f,delimiter ='\ t'); rows = list(reader);打印(行);' –

回答

1

只是爲了它的緣故,這是你如何解析這個格式 「自動地」:

import re 

# find out spaces' positions common to all rows 
spaces = sorted(set.intersection(*[ 
    set(m.end() for m in re.finditer(ur'\s', line)) 
    for line in data 
])) 

# split by these positions 
for line in data: 
    row = [] 
    p = 0 
    for s in spaces: 
     row.append(line[p:s]) 
     p = s 
    row.append(line[p:]) 
    row = filter(len, map(unicode.strip, row)) 
    print ' | '.join(row) # or whatever you want... 

爲您的數據:

data = u""" 
Clnr Kontonr  Konto    Valuta Bokföringsdatum Transaktionsdatum Referens       Kontohändelse     Belopp 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   Hyresgästför      Autogiro      -15,00 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   SPOTIFY SPOTIFY      Kortköp/uttag     -19,00 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   +46123456789      Swish mottagen     80,00 
12345 1234567890 vardagskonto   SEK  13-09-30   13-09-30   PRIS NYCKELKUND      Debiteringsavgift    -49,00 
12345 1234567890 vardagskonto   SEK  13-09-27   13-09-27   12345678       direktbetalning    -301,00 
12345 1234567890 vardagskonto   SEK  13-09-27   13-09-27   Unionen        Bg-bet. via internet   -125,00 
12345 1234567890 vardagskonto   SEK  13-09-26   13-09-26   123456789Överföring     -1 000,00 
""".strip().splitlines() 

此打印:

Clnr | Kontonr | Konto | Valuta | Bokföringsdatum | Transaktionsdatum | Referens | Kontohändelse | Belopp 
12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | Hyresgästför | Autogiro | -15,00 
12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | SPOTIFY SPOTIFY | Kortköp/uttag | -19,00 
12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | +46123456789 | Swish mottagen | 80,00 
12345 | 1234567890 | vardagskonto | SEK | 13-09-30 | 13-09-30 | PRIS NYCKELKUND | Debiteringsavgift | -49,00 
12345 | 1234567890 | vardagskonto | SEK | 13-09-27 | 13-09-27 | 12345678 | direktbetalning | -301,00 
12345 | 1234567890 | vardagskonto | SEK | 13-09-27 | 13-09-27 | Unionen | Bg-bet. via internet | -125,00 
12345 | 1234567890 | vardagskonto | SEK | 13-09-26 | 13-09-26 | 123456789| Överföring | -1 000,00 
+0

我希望我能理解您的解決方案的第一點,但我真的很喜歡您的解決方案適用於任意間隔輸入。不過,我最終使用了更簡單的方法。 – monotux

-1

爲什麼不這個表達式:

(.*?)( +|\r\n|\n|$) 

似乎所有列由2位

1

分隔您可以使用re.split分隔這些值,例如:

import re 

raw_data = open("test.csv").readlines() 
header = raw_data[0] 
data = raw_data[1:] 

for line in data: 
     values = re.split("\s{2,}", line.strip()) # splits by two or more spaces 
     print list(values) # show as a list 
+0

這就是我最終使用的,謝謝! thg435提出的解決方案更好,但我完全理解。 – monotux