2016-12-02 61 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 
    .... 

但是,這是非常複雜的,容易出錯,而不是Python的根本。

下一個方法是從數據列表中提取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 

這個工程,是一個更容易實現且不易出錯以前的解決方案,但似乎並沒有很符合Python或者。

使用列表理解可以做到這一點嗎?喜歡的東西:

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

但後來,我怎麼讓for列表中的理解有時向前跳1,有時向前5

是否還有其他可能,Python的方式來實現這一目標?

+0

我的第一直覺就是使用're'可靠地匹配每個字符串,和一個列表理解或循環將其應用到列表中的所有字符串。另一種選擇是將所有字符串連接成一個大字符串(或字符串塊)並使用更全面的're'匹配器(多行?) – hpaulj

+0

我得到的第二個建議(特別是在看到@double_j的答案之後)。你的第一個建議我沒有得到,特別是列表理解部分。例如,可以有一行中的3個日期,其中只有最後兩個日期可以是我正在尋找的整體模式的一部分。你如何匹配5個模式的序列?你不知何故必須「記住」列表理解期間你從列表中刪除的項目。 – NZD

回答

2

你的第二個解決方案看起來很好。我會將其更改爲發生器(yield您發現的切片),但不會更多。

儘管如此,您也可以通過在片段的項目編號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']] 
相關問題