使用大十进制在Python中解析固定宽度的文件

时间:2019-08-08 16:33:50

标签: python python-3.x csv struct

我必须在python中解析以下文件:

20100322;232400;1.355800;1.355900;1.355800;1.355900;0
20100322;232500;1.355800;1.355900;1.355800;1.355900;0
20100322;232600;1.355800;1.355800;1.355800;1.355800;0

我需要以以下变量结尾(以第一行为例):

year = 2010
month = 03
day = 22
hour = 23
minute = 24
p1 = Decimal('1.355800')
p2 = Decimal('1.355900')
p3 = Decimal('1.355800')
p4 = Decimal('1.355900')

我尝试过:

line = '20100322;232400;1.355800;1.355900;1.355800;1.355900;0'
year = line[:4]
month = line[4:6]
day = line[6:8]
hour = line[9:11]
minute = line[11:13]
p1 = Decimal(line[16:24])
p2 = Decimal(line[25:33])
p3 = Decimal(line[34:42])
p4 = Decimal(line[43:51])

print(year)
print(month)
print(day)
print(hour)
print(minute)
print(p1)
print(p2)
print(p3)
print(p4)

哪个可以很好地工作,但是我想知道是否有一种更简单的方法来解析它(也许使用struct),以避免必须手动计算每个位置。

2 个答案:

答案 0 :(得分:2)

from decimal import Decimal
from datetime import datetime

line = "20100322;232400;1.355800;1.355900;1.355800;1.355900;0"

tokens = line.split(";")

dt = datetime.strptime(tokens[0] + tokens[1], "%Y%m%d%H%M%S")
decimals = [Decimal(string) for string in tokens[2:6]]

# datetime objects also have some useful attributes: dt.year, dt.month, etc.
print(dt, *decimals, sep="\n")

输出:

2010-03-22 23:24:00
1.355800
1.355900
1.355800
1.355900

答案 1 :(得分:0)

您可以使用正则表达式:

import re

to_parse = """
20100322;232400;1.355800;1.355900;1.355800;1.355900;0
20100322;232500;1.355800;1.355900;1.355800;1.355900;0
20100322;232600;1.355800;1.355800;1.355800;1.355800;0
"""

stx = re.compile(
    r'(?P<date>(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2}));'
    r'(?P<time>(?P<hour>\d{2})(?P<minute>\d{2})(?P<second>\d{2}));' 
    r'(?P<p1>[\.\-\d]*);(?P<p2>[\.\-\d]*);(?P<p3>[\.\-\d]*);(?P<p4>[\.\-\d]*)'
    )

f = [{k:float(v) if 'p' in k else int(v) for k,v in a.groupdict().items()} for a in stx.finditer(to_parse)]

print(f)

输出:

[{'date': 20100322,
  'day': 22,
  'hour': 23,
  'minute': 24,
  'month': 3,
  'p1': 1.3558,
  'p2': 1.3559,
  'p3': 1.3558,
  'p4': 1.3559,
  'second': 0,
  'time': 232400,
  'year': 2010},
 {'date': 20100322,
  'day': 22,
  'hour': 23,
  'minute': 25,
  'month': 3,
  'p1': 1.3558,
  'p2': 1.3559,
  'p3': 1.3558,
  'p4': 1.3559,
  'second': 0,
  'time': 232500,
  'year': 2010},
 {'date': 20100322,
  'day': 22,
  'hour': 23,
  'minute': 26,
  'month': 3,
  'p1': 1.3558,
  'p2': 1.3558,
  'p3': 1.3558,
  'p4': 1.3558,
  'second': 0,
  'time': 232600,
  'year': 2010}]

这里我将所有内容存储在列表中,但是如果您不想将所有内容存储在内存中,则实际上可以逐行查看finditer的结果。

如果需要,还可以用Decimal替换fload和/或int