Python: Generic Algorithmic to determine fixed length columns
I am trying to write a generic function to be able to read a fixed length file. I could go through and hand count the length between columns, and then read the file, but I was wondering if there was a way to do it programmatically开发者_开发知识库.
I can see what needs to be done, but I am not sure the proper way to do it...
If I have a file like:
ColA ColB ColC FinalCol
1 22 23 ColumnsCnBTxt
213 1 2 2
11213 11111 1234567890 3
All of the headers are "right justified" and seperated by spaces (not tabs), so I basically just need to count from StartIndex to last Character and that is my column length.
Is there any easy way to achieve this in python? The resulting object would be a list of column lengths
header_line = " ColA ColB ColC FinalCol"
result = get_header_information(header_line)
#result = (5,5, 10, 13)
One-liner using regex splits:
>>> map(len, re.split(r"(?<=[^ ]) ", head))
[5, 5, 10, 13]
Explanation:
re.split
splits a string at all points where a regular expression matches. The regular expression I use (others would be possible) has a lookbehind group (?<=[^ ])
which means "preceded by a non-space" and then a space, so matches spaces which are preceded by non-spaces. This will split the string into the column headers, and then we simply take the lengths of the resulting strings.
Notice that this is not performance-optimal -- we are making three passes through the string and invoking a regex engine -- but for normal-size strings that's fine.
Using the re
module, you could do
header = " ColA ColB ColC FinalCol"
endcols = [m.end() for m in re.finditer("[^ ]+", header)]
widths = [j - i for i, j in zip([0] + endcols, endcols)]
# [5, 6, 11, 14]
(Note that the column widths differ slightly from the numbers you gave in your answer, but I actually don't really understand why you'd expect those numbers.)
If, as it seems,
- You always have at least one space between fields.
- No field value contains an embedded space.
Then just split each line something like:
f = file('filename', 'r')
table = [line.strip().split() for line in f]
f.close()
If a field is either an int or text then you could modify the table line to become:
table = [[(int(field) if all(ch in '0123456789' for ch in field) else field)
for field in line.strip().split()]
for line in f]
精彩评论