Есть большой массив данных.
Пример строки из массива:
20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0
Где первые два значения — номер метеостанции и год, остальные — температуры воздуха, начиная с января. Значения разделяются пробелами, при этом количество пробелов варьируется от 1 до 3. Значения температур, которые не были зафиксированы метеостанцией заменяется пробелами, т.е. в массиве допускается строка вида:
20667 2014 5.5 2.4 7.9 8.1 42.7 10.1
Необходима регулярка, которая бы разбивала эту строку на массив вида:
['20667','2014','5.5','2.4','7.9','8.1','','','42.7','','','10.1','','']
Регулярное выражение для вашей первой строки, чтобы вы поняли как ещё можно работать с регулярками помимо стандартных \d\w\s +*?
. Очень наглядно и интуитивно:
(\d{5})[ ]{1,3}(\d{4})[ ]{1,3}([0-9.]{4})[ ]{1,3}(([0-9.]{4}))[ ]{1,3}([0-9.]{3})[ ]{1,3}([0-9.]{4})[ ]{1,3}([0-9.]{3})[ ]{1,3}([0-9.]{3})[ ]{1,3}([0-9.]{3})[ ]{1,3}([0-9.]{4})[ ]{1,3}([0-9.]{4})[ ]{1,3}([0-9.]{4})[ ]{1,3}([0-9.]{4})[ ]{1,3}([0-9.]{4})
Версия, которая найдёт все строки:
(([0-9.]{1,5})([ ]{1,3})?)+?
По описанию ваших входных данных, похоже что это fixed-width
файл.
В этом случае будет очень удобно воспользоваться Pandas модулем:
import pandas as pd cols = ['id', 'year'] + ['m{}'.format(i) for i in range(1, 13)] df = pd.read_fwf(r'D:\temp\.data\655212.txt', header=None, names=cols) print(df)
Результат:
In [136]: df Out[136]: id year m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 0 20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0 1 20047 2005 26.5 NaN 7.5 17.3 NaN NaN 10.2 39.9 19.7 NaN 20.4 20.0
Также можно воспользоваться идеей от @jfs для того чтобы назвать столбцы по именам месяцев:
import calendar cols = ['id', 'year'] + list(calendar.month_abbr)[1:] df = pd.read_fwf(r'D:\temp\.data\655212.txt', header=None, names=cols)
Результат:
In [139]: df Out[139]: id year Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec 0 20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0 1 20047 2005 26.5 NaN 7.5 17.3 NaN NaN 10.2 39.9 19.7 NaN 20.4 20.0
Исходный файл:
20046 2005 27.0 44.3 9.0 15.9 3.6 9.2 9.2 37.5 18.3 18.6 24.4 26.0 20047 2005 26.5 7.5 17.3 10.2 39.9 19.7 20.4 20.0
Предполагая, что под каждую температуру месяца отводится ровно 6 позиций (фиксированная ширина полей), можно распознать данные со стандартного ввода или из файлов, заданных в командной строчке, используя fileinput
стандартный модуль:
#!/usr/bin/env python import fileinput width = 6 for line in fileinput.input(): station_id, year, s = line.split(None, 2) s = s.rstrip('\n').rjust(12 * width) # pad with leading space temps = [s[i:i+width].strip() for i in range(0, len(s), width)] print(temps)
Пример
$ python parse-fixed-width-temps.py input.txt ['27.0', '44.3', '9.0', '15.9', '3.6', '9.2', '9.2', '37.5', '18.3', '18.6', '24.4', '26.0'] ['5.5', '2.4', '7.9', '8.1', '', '', '42.7', '', '', '10.1', '', '']
Если предположить, что каждая строка имеет фиксированную длину (82 символа), и под каждый месяц в строке отведено 5 символов (XX.XX), получаем, что разделителем должны быть два пробельных символа.
Значит, можно заменить лишние пробелы на отсутствующее значение + пробелы-разделители, и попробовать поделить строку следующим образом:
data = '20667 2014 5.5 2.4 7.9 8.1 42.7 10.1 ' print [val.strip() for val in data.replace(' ', ' n/d ').split(' ')] >>> ['20667 2014', '5.5', '2.4', '7.9', '8.1', 'n/d', 'n/d', '42.7', 'n/d', 'n/d', '10.1', 'n/d', 'n/d']