【问题标题】:parsing text file with JSON-like object into CSV将具有类 JSON 对象的文本文件解析为 CSV
【发布时间】:2013-03-04 21:08:59
【问题描述】:

我有一个包含键值对的文本文件,最后两个键值对包含类似 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}

我们最终想出了一些可行的方法,但一定有更好的方法:

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

我们不想在未来编写这样的代码。

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

【问题讨论】:

  • 该输入格式与 JSON 完全不同。唯一认为远程相关的是花括号和逗号,但比较到此结束。
  • 我想前几天有人问过这样的问题,我会试着找到它。或者也许这是这个问题的延续?编辑:(stackoverflow.com/questions/15190260/…)

标签: python json csv


【解决方案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 个扩展标题。

【讨论】:

  • 不错的答案。你有什么理由更喜欢'if not i'而不是'if i == 0'?对我来说,您不是在问“它存在吗?”,而是在检查它是否是值 0。
  • @daveydave400:数字 0 在 Python 中始终为假。空序列和集合(字典、集合、列表、元组、字符串等)也是如此。在我看来它更容易更干净。
  • 我知道它是准确的并且空序列评估为假,我个人只是在实际检查值时更喜欢“== X”,并且想知道除了偏好之外是否还有其他原因。当我检查空序列时,我使用“not X”,如果检查 None “is None”或“is not None”。
  • @daveydave400:明确测试None 的原因不同;您可能希望允许 0 但不允许 None。这里没有歧义; enumerate() 从 0 开始。
  • Martijn,我从您的解决方案中学到了很多东西。这是关于 SO 的最好的事情。加上它的工作原理!非常感谢。 -丰富
猜你喜欢
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多