2013-03-04 94 views
0

我有一個包含鍵值對的文本文件,最後兩個鍵值對包含類似JSON的對象,我想將其拆分爲列並使用其他值,使用鍵作爲列標題。前三行中的數據文件input.txt的是這樣的:將帶有類JSON對象的文本文件解析爲CSV

InnerDiameterOrWidth::0.1,InnerHeight::0.1,Length2dCenterToCenter::44.6743867864386,Length3dCenterToCenter::44.6768028159989,Tag::<NULL>,{StartPoint::7858.35924983374[%2C]1703.69341358077[%2C]-3.075},{EndPoint::7822.85045874375[%2C]1730.80294308742[%2C]-3.53962362760298} 
InnerDiameterOrWidth::0.1,InnerHeight::0.1,Length2dCenterToCenter::57.8689351603823,Length3dCenterToCenter::57.8700464193429,Tag::<NULL>,{StartPoint::7793.52927597915[%2C]1680.91224357457[%2C]-3.075},{EndPoint::7822.85045874375[%2C]1730.80294308742[%2C]-3.43363070193163} 
InnerDiameterOrWidth::0.1,InnerHeight::0.1,Length2dCenterToCenter::68.7161350545728,Length3dCenterToCenter::68.7172034962765,Tag::<NULL>,{StartPoint::7858.35924983374[%2C]1703.69341358077[%2C]-3.075},{EndPoint::7793.52927597915[%2C]1680.91224357457[%2C]-3.45819643838485} 

,我們終於想出了一些工作,但必須有一個更好的方法:

import csv 
with open('input.txt', 'rb') as fin, open('output.csv', 'wb') as fout: 
    reader = csv.reader(fin) 
    writer = csv.writer(fout) 
    for i, line in enumerate(reader): 
     mysplit = [item.split('::') for item in line if item.strip()] 
     if not mysplit: # blank line 
      continue 
     keys, vals = zip(*mysplit) 
     start_vals = [item.split('[%2C]') for item in mysplit[-2]] 
     end_vals = [item.split('[%2C]') for item in mysplit[-1]] 
     a=list(keys[0:-2]) 
     a.extend(['start1','start2','start3','end1','end2','end3']) 
     b=list(vals[0:-2]) 
     b.append(start_vals[1][0]) 
     b.append(start_vals[1][1]) 
     b.append(start_vals[1][2][:-1]) 
     b.append(end_vals[1][0]) 
     b.append(end_vals[1][1]) 
     b.append(end_vals[1][2][:-1]) 
     if i == 0: 
      # if first line: write header 
      writer.writerow(a) 
     writer.writerow(b) 

產生輸出文件output.csv,看起來像這樣

InnerDiameterOrWidth,InnerHeight,Length2dCenterToCenter,Length3dCenterToCenter,Tag,start1,start2,start3,end1,end2,end3 
0.1,0.1,44.6743867864386,44.6768028159989,<NULL>,7858.35924983374,1703.69341358077,-3.075,7822.85045874375,1730.80294308742,-3.53962362760298 
0.1,0.1,57.8689351603823,57.8700464193429,<NULL>,7793.52927597915,1680.91224357457,-3.075,7822.85045874375,1730.80294308742,-3.43363070193163 
0.1,0.1,68.7161350545728,68.7172034962765,<NULL>,7858.35924983374,1703.69341358077,-3.075,7793.52927597915,1680.91224357457,-3.45819643838485 

我們不想寫這樣的代碼在未來。

什麼是閱讀這樣的數據的最佳方式是什麼?

+1

沒有什麼類似JSON的輸入格式。唯一與遠程相關的思想是花括號和逗號,但比較結束。 – 2013-03-04 21:10:33

+1

我想幾天前有人問過這樣的問題,我會盡力找到它。或者,也許這是這個問題的延續?編輯:(http://stackoverflow.com/questions/15190260/python-csv-read-write-remove-and-replace-plus-end-of-line-is-json-format/15190741) – daveydave400 2013-03-04 21:25:29

回答

1

我會使用:

from itertools import chain 
import csv 

_header_translate = { 
    'StartPoint': ('start1', 'start2', 'start3'), 
    'EndPoint': ('end1', 'end2', 'end3') 
} 

def header(col): 
    header = col.strip('{}').split('::', 1)[0] 
    return _header_translate.get(header, (header,)) 

def cleancolumn(col): 
    col = col.strip('{}').split('::', 1)[1] 
    return col.split('[%2C]') 

def chainedmap(func, row): 
    return list(chain.from_iterable(map(func, row))) 

with open('input.txt', 'rb') as fin, open('output.csv', 'wb') as fout: 
    reader = csv.reader(fin) 
    writer = csv.writer(fout) 
    for i, row in enumerate(reader): 
     if not i: # first row, write header first 
      writer.writerow(chainedmap(header, row)) 
     writer.writerow(chainedmap(cleancolumn, row)) 

cleancolumn方法需要你的任何列,並且去掉括號,第一::和分裂的前去除一切後,返回一個元組(可能只有一個值)嵌入'逗號'。通過使用itertools.chain.from_iterable(),我們再次將csv編寫器中從列中生成的一系列元組轉換爲一個列表。

當處理第一行時,我們從相同的列中生成一個標題行,將StartPointEndPoint標題替換爲6個擴展標題。

+0

好的答案。任何你喜歡的原因'如果不是我'結束'如果我=='?對我來說,你並不是問「它是否存在?」,你正在檢查它是否爲值0. – daveydave400 2013-03-04 21:34:48

+0

@ daveydave400:Python中的numeric 0總是爲false。所以是空序列和集合(字典,集合,列表,元組,字符串等)。我的眼睛更輕鬆,更清潔。 – 2013-03-04 21:35:12

+0

我知道這是準確的,並且空序列評估爲false,當我真正檢查一個值時,我個人更喜歡「== X」,並且想知道除了偏好之外是否還有其他原因。當我檢查空序列時,如果檢查無是「無」或「不是無」,則使用「不是X」。 – daveydave400 2013-03-04 21:39:43