Самый простой способ разобрать это - просто взять все значения x и y, а затем соединить их вместе.
Конечно, может быть проблема, когда есть значение x, но нет соответствующее значение y. В этом случае вам нужно будет знать, когда вы «начинаете» и «заканчиваете» новую группу значений.
#!/usr/bin/env python
import re
SAMPLE_TEXT = '''
< begin >
< datapt > 1 < datapt >
< xunit > mass < xunit >
< xval > 150.000097 < xval >
< yunit > abs < yunit >
< yval > 0.000000 < yval >
< end >
< begin >
< datapt > 2 < datapt >
< xunit > mass < xunit >
< xval > 150.000245 < xval >
< yunit > abs < yunit >
< yval > 0.000000 < yval >
< end >
'''
num_tag_pattern = lambda key: re.compile('<\s*' + key + '\s*>\s*(\d[.\d]+)\s*<\s*' + key + '\s*>')
x_pat, y_pat = num_tag_pattern('xval'), num_tag_pattern('yval')
def parse_points(text):
x_vals, y_vals = [], []
for line in text.strip().split('\n'):
parse_float(line.strip(), x_pat, x_vals)
parse_float(line.strip(), y_pat, y_vals)
return list(zip(x_vals, y_vals))
def parse_float(line, pattern, values):
m = pattern.match(line.strip())
if m is not None:
values.append(float(m[1]))
if __name__ == '__main__':
print(parse_points(SAMPLE_TEXT)) # [(150.000097, 0.0), (150.000245, 0.0)]
Обновление
Вот более общий c, более безопасная версия, которая фактически анализирует исходные данные в JSON перед преобразованием их в точки.
Я даже добавил исключения, если есть какие-либо отсутствующие теги.
main.py
#!/usr/bin/env python
import re
TAG_BEGIN = re.compile(r'<\s*begin\s>', re.IGNORECASE)
TAG_END = re.compile(r'<\s*end\s>', re.IGNORECASE)
TAG_DATA = re.compile(r'<\s*(\w+)\s*>\s*(.+)\s*<\s*\1\s*>')
def parse_to_json(fname, strict=True):
records, curr_record = [], None
with open(fname) as fp:
for line in fp:
m = TAG_BEGIN.match(line.strip())
if m is not None:
if curr_record is not None:
raise Exception('previous object was not closed, missing <END> tag')
curr_record = {}
continue
m = TAG_END.match(line.strip())
if m is not None:
if curr_record is None:
raise Exception('missing <BEGIN> tag')
records.append(curr_record)
curr_record = None
continue
m = TAG_DATA.match(line.strip())
if m is not None:
if curr_record is None:
raise Exception('previous object closed, missing <BEGIN> tag')
curr_record[m[1]] = m[2]
if strict:
if curr_record is not None:
raise Exception('reached EOF, missing <END> tag')
else:
if curr_record is not None:
records.append(curr_record) # Just add what we got...
return records
def map_to_point(record, x_field, y_field):
return (
float(record[x_field]) if x_field in record else 0.0,
float(record[y_field]) if y_field in record else 0.0
)
def parse_points(fname, x_field='x', y_field='y', strict=True):
return list(map(lambda record: map_to_point(record, x_field, y_field), parse_to_json(fname, strict)))
if __name__ == '__main__':
print(parse_points('data.txt', x_field='xval', y_field='yval', strict=True))
data.txt
< begin >
< datapt > 1 < datapt >
< xunit > mass < xunit >
< xval > 150.000097 < xval >
< yunit > abs < yunit >
< yval > 0.000000 < yval >
< end >
< begin >
< datapt > 2 < datapt >
< xunit > mass < xunit >
< xval > 150.000245 < xval >
< yunit > abs < yunit >
< yval > 0.000000 < yval >
< end >