Python 将具有类似JSON对象的文本文件解析为CSV

Python 将具有类似JSON对象的文本文件解析为CSV,python,json,csv,Python,Json,Csv,我有一个包含键值对的文本文件,最后两个键值对包含类似JSON的对象,我希望将这些对象拆分为列,并使用其他值编写,使用键作为列标题。数据文件input.txt的前三行如下所示: InnerDiameterOrWidth::0.1,InnerHeight::0.1,Length2dCenterToCenter::44.6743867864386,Length3dCenterToCenter::44.6768028159989,Tag::<NULL>,{StartPoint::7858.3

我有一个包含键值对的文本文件,最后两个键值对包含类似JSON的对象,我希望将这些对象拆分为列,并使用其他值编写,使用键作为列标题。数据文件
input.txt
的前三行如下所示:

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}
它生成输出文件
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
innerdiameterwidth,InnerHeight,Length2dCenterToCenter,Length3dCenterToCenter,Tag,start1,start2,start3,end1,end2,end3
0.1,0.1,44.6743867864386,44.6768028159989,,7858.35924983374,1703.69341358077,-3.075,7822.85045874375,1730.80294308742,-3.53962362760298
0.1,0.1,57.8689351603823,57.8700464193429,,7793.52927597915,1680.91224357457,-3.075,7822.85045874375,1730.80294308742,-3.43363070193163
0.1,0.1,68.7161350545728,68.7172034962765,,7858.35924983374,1703.69341358077,-3.075,7793.52927597915,1680.91224357457,-3.45819643838485
我们不想在将来编写这样的代码

读取此类数据的最佳方法是什么?

我会使用:

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编写器的一个列表


在处理第一行时,我们从相同的列生成一个标题行,用6个扩展标题替换
StartPoint
EndPoint
标题。

该输入格式与JSON完全不同。唯一与之相关的是花括号和逗号,但比较到此为止。我想几天前有人问了一个类似的问题,我会努力找到它。或者这是这个问题的延续?编辑:()回答得好。你为什么喜欢“如果不是我”而不是“如果我==0”?对我来说,你不是在问“它存在吗?”,而是在检查它是否是值0。@daveydave400:numeric 0在Python中始终为false。空序列和集合(dict、set、list、tuple、string等)也是如此。在我看来,它更简单、更清晰。我知道它是准确的,空序列的计算结果为假,我个人只是在实际检查值时更喜欢“==X”,我想知道除了偏好之外,您是否还有其他原因。当我检查空序列时,我使用“not X”,如果检查None“为None”或“为None”。@daveydave400:有一个不同的理由来显式测试
None
;您可能希望允许
0
,但不允许
None
。这里没有歧义<代码>枚举()从0开始。Martijn,我从您的解决方案中学到了很多。这是最好的事情。加上它的工作!非常感谢-富有的
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))