我正在尝试将此以空格分隔的文本文件转换为列和行(我想最终将其转换为JSON)。我的脚本可能无法分隔cols,主要是因为我正在寻找空白。我无法更改输入的格式(文本文件进来了)
我在文件格式方面遇到问题,这是一个非常简单的示例
col1 col2 col3 text col4
1403 bash 2014-07-28 22:32:53 UTC+0000 sudo bash
1464 bash 2014-07-28 22:32:28 UTC+0000 sudo root
当我解析文件时,我得到的是破折号下方的数据:
['1403', 'bash', '2014-07-28', '22:32:53', 'UTC+0000', 'sudo', 'bash']
我希望它看起来像这样:
['1403', 'bash', '2014-07-28 22:32:53 UTC+0000', 'sudo bash']
这是一个非常基本的示例。但基本上我是将标头映射到破折号下方的数据。让我知道您是否可以提供任何帮助。
注意:输出不必完全如图所示,我只希望能够分离cols数据。
到目前为止,这是我在代码中所拥有的,这将标题分隔为各个cols:
colNames = testFile.readline()
#tempList = re.split('(\s )', colNames)
headerList = []
for i in tempList:
j = i.replace(' ','')
if j != '':
headerList.append(j)
然后我有一个循环,可以根据数据的位置浏览数据(这是我认为需要找到一种更好地分离数据的方法):
for line in testFile.readlines():
if rowCounter > 0:
row = line.split()
print row
for i in range(len(headerList)):
colNameDic.update({headerList[i]:row[i]})
rowDic = dict(colNameDic)
fileList.append(rowDic)
rowDic = {}
rowCounter +=1
答案 0 :(得分:0)
只要列宽是固定的,就可以使用固定宽度的解析器:
pd.read_fwf(io.StringIO(data), skiprows=[1],
parse_dates=["col3 text"], # Optional
colspecs=[(0,4),(5,25),(26,54),(57,66)])
# col1 col2 col3 text col4
#0 1403 bash 2014-07-28 22:32:53 sudo bash
#1 1464 bash 2014-07-28 22:32:28 sudo root
答案 1 :(得分:0)
如果标题行的列名中没有外部空格,则可以使用slice
内置函数来分割数据行(请注意,我在下划线中添加了下划线标题行以标准化列名)
In [20]: h = 'col1 col2 col3_text col4\n'
In [21]: r = '1403 bash 2014-07-28 22:32:53 UTC+0000 sudo bash\n'
In [22]: fields = h.split()
...: ifields = [h.index(f) for f in fields]+[None]
In [23]: slices = [slice(i,j) for i, j in zip(ifields, ifields[1:])]
In [24]: tokens = [r[s] for s in slices]
In [25]: tokens
Out[25]:
['1403 ',
'bash ',
'2014-07-28 22:32:53 UTC+0000 ',
'sudo bash\n']
In [26]:
您可能需要rstrip
[r[s].rstrip() for s in slices]
的各个项目。
附录
如果可以在有效的列名和垃圾之间找到区别,则可以放宽对多余空间的要求...重新设置您的特定数据格式(不带下划线...)
In [35]: h = 'col1 col2 col3 text col4\n'
In [36]: r = '1403 bash 2014-07-28 22:32:53 UTC+0000 sudo bash\n'
In [37]: fields = [f for f in h.split() if f[:3]=='col']
In [38]: ifields = [h.index(f) for f in fields]+[None]
In [39]: slices = [slice(i,j) for i, j in zip(ifields, ifields[1:])]
In [40]: tokens = [r[s].rstrip() for s in slices]
In [41]: tokens
Out[41]: ['1403', 'bash', '2014-07-28 22:32:53 UTC+0000', 'sudo bash']
In [42]:
答案 2 :(得分:0)
这是另一种方法:对文本行进行两次通过处理。在第一遍中,我们将猜测起始索引:非空格字符前面带有空格的索引。对于每一行,开始索引可能会略有不同,但是如果我们查看所有它们都全部相同的索引,则这些索引可能是列的开始。起始索引的猜测并不完美。它要求一行中的任何单元都不丢失
在第二遍中,我们将使用这些索引将行拆分为列,以修剪尾随空白。
import itertools
def split_columns(row, start_indices):
start_indices = start_indices + [None]
a, b = iter(start_indices), iter(start_indices)
next(b)
columns = []
for istart, istop in zip(a, b):
columns.append(row[slice(istart, istop)].strip())
return columns
def guess_start_indices(row):
row = ' ' + row
prev_seq, cur_seq = iter(row), iter(row)
next(cur_seq)
start_indices = []
for i, (prev, cur) in enumerate(zip(prev_seq, cur_seq)):
if prev == ' ' and cur != ' ':
start_indices.append(i)
return set(start_indices)
def find_common_start_indices(rows):
start_indices = set.intersection(*(guess_start_indices(row) for row in rows))
start_indices = sorted(start_indices)
return start_indices
if __name__ == '__main__':
with open('columnize.txt') as rows:
first_pass, second_pass = itertools.tee(rows)
start_indices = find_common_start_indices(first_pass)
print(start_indices)
for row in second_pass:
print(split_columns(row, start_indices))
注释
first_pass
和second_pass
来帮助迭代文本行。这些迭代器很重要,因为它们允许对行进行两次迭代,而无需回退文件。