2016-12-02 5 views
2

У меня есть большой набор данных в списке. Список состоит из коротких строк. Внутри списка находятся кусочки длиной 5 скрытые, которые соответствуют определенному шаблону:Python2.7: Извлечь фрагмент из списка на основе шаблона в Pythonic

[<date>, <date>, <4 digit integer>, <string>, <$ amount>] 

Как я могу извлечь эти кусочки из моих наборов данных? Они могут встречаться в любом месте (поэтому их индекс не может быть кратным 5) и чередуются с другими данными (также строками), которые могут соответствовать части шаблона.

я начал что-то похожее на:

for item in data: 
    if re.search(<date pattern>, item): 
     if not date1: 
      date1 = item 
     else: 
      date2 = item 
    if re.search(<4 digit integer pattern>, item): 
     if date1 and date2 and not fourdigit: 
      fourdigit = item 
     else: 
      date1 = None 
      date2 = None 
    .... 

Но это очень сложно, склонной к ошибкам и не вещий вообще.

Следующим подходом было извлечение скользящего окна из 5 элементов из списка данных и проверка соответствия всех элементов их шаблону. Если нет, увеличьте индекс на 1 (т. Е. Сдвиньте окно на 1) и проверьте следующий фрагмент. Если шаблон соответствует, за исключением среза, и увеличиваем индекс на 5. Что-то вроде:

index = 0 
while index < (len(data)-5): 
    sliceof5 = data[index:index+5] 
    if slice_matches_pattern(sliceof5): 
     matching_items.append(sliceof5) 
     index += 5 
    else: 
     index += 1 

Это работает и намного проще в реализации и меньше ошибок предыдущее решение, но, кажется, не очень вещий либо ,

Возможно ли это сделать, используя понимание списка? Что-то вроде:

matching_items = [ sliceof5 if slice_matches_pattern(sliceof5) for sliceof5 in data ] 

Но тогда, как я делаю for в списке понимании иногда пропустить вперед 1, а иногда и вперед 5.

Есть, возможно, другие, вещие пути для достижения этой цели?

+0

Моим первым инстинктом является использование 're' для надежного сопоставления каждой строки, а также понимание или цикл списка, чтобы применить его ко всем строкам в списке. Другой вариант - объединить все строки в одну большую строку (или блоки строк) и использовать более полный 're' matcher (multiline?) – hpaulj

+0

Второе предложение, которое я получаю (особенно после просмотра ответа @double_j). Ваше первое предложение, которое я не получаю, особенно часть понимания списка. Например, могут быть три даты, в ряду которых только два последних могут быть частью общей картины, которую я ищу. И как вы соответствуете последовательности из 5 шаблонов? Вы как-то должны «помнить» предметы, которые вы вытащили из списка во время понимания списка. – NZD

ответ

2

Ваше второе решение кажется прекрасным. Я бы сменил его на генератор (ломтики, которые вы найдете), но не более.

Возможно, вы можете запустить его быстрее, хотя, ища дату в позиции номер 2 среза. Если это не дата, вы можете добавить два в индекс.

Конечно, если вы можете превратить все в одно большое регулярное выражение, соответствующее вашему шаблону, вы сделаете еще лучше.

2

Не имея представления о том, как выглядят ваши данные, следуя идее @ hpaulj, мы предлагаем подход с регулярным выражением.

import re 

data = [ 
    '2016-12-01', '2016-12-02', '1234', 'spam', '$100', # collect 
    '2016-12-02', 'spam', # discard 
    '2016-12-01', '2016-12-02', '1234', 'spam', '$100', # collect 
    '1234', '2016-12-01', # discard 
    '2016-12-01', '2016-12-02', '1234', 'spam', '$100', # collect 
    '$100', '1234', '1234', # discard 
    '2016-12-01', '2016-12-02', '1234', 'spam', '$100' # collect 
] 

pattern_sep_str = '||' # change to something unique in the data 

pattern_sep = re.escape(pattern_sep_str) 
date_pattern = r'[0-9]{4}-[0-9]{2}-[0-9]{2}' 
int_pattern = r'[0-9]{4}' 
str_pattern = r'[a-zA-Z]+' 
amount_pattern = r'\$[0-9,.]+' 

pattern_combined = ''.join([ 
    '(', date_pattern, pattern_sep, date_pattern, pattern_sep, 
    int_pattern, pattern_sep, str_pattern, pattern_sep, 
    amount_pattern, ')' 
]) 

results = re.findall(pattern_combined, pattern_sep_str.join(data)) 

print([x.split(pattern_sep_str) for x in results]) 

>>> [['2016-12-01', '2016-12-02', '1234', 'spam', '$100'], ['2016-12-01', '2016-12-02', '1234', 'spam', '$100'], ['2016-12-01', '2016-12-02', '1234', 'spam', '$100'], ['2016-12-01', '2016-12-02', '1234', 'spam', '$100']] 
Смежные вопросы