2015-12-22 48 views
7

我有一個像這樣的字符串列表的字符串,分割基於一組特定的詞

['happy_feet', 'happy_hats_for_cats', 'sad_fox_or_mad_banana','sad_pandas_and_happy_cats_for_people'] 

給定一個關鍵字列表一樣['for', 'or', 'and']我希望能夠在那裏,如果到列表解析成另一個列表關鍵字列表出現在字符串中,將該字符串拆分爲多個部分。

例如,上面的設置將被分成

['happy_feet', 'happy_hats', 'cats', 'sad_fox', 'mad_banana', 'sad_pandas', 'happy_cats', 'people'] 

目前我已經分裂用下劃線每個內部字符串,並有一個for循環尋找一個關鍵字的索引,然後重新組合的字符串下劃線。有沒有更快的方法來做到這一點?

+1

這實際上可能相當快。你的應用程序太慢了嗎? – TigerhawkT3

+0

不是真的,我只是一種新的Python,並不知道是否有更好,更簡潔的方式來做到這一點。 – SharpObject

+1

我通常建議在優化之前進行測量。 :)無論如何,基本的字符串操作通常比更復雜的方法更快。 – TigerhawkT3

回答

6
>>> pat = re.compile("_(?:%s)_"%"|".join(sorted(split_list,key=len))) 
>>> list(itertools.chain(pat.split(line) for line in data)) 

會給你提供的示例數據集

你不要在 _分隔符

實際所需的輸出真的需要按照長度排序,所以你可以做

>>> pat = re.compile("_(?:%s)_"%"|".join(split_list)) 
>>> list(itertools.chain(pat.split(line) for line in data)) 
6
>>> [re.split(r"_(?:f?or|and)_", s) for s in l] 
[['happy_feet'], 
['happy_hats', 'cats'], 
['sad_fox', 'mad_banana'], 
['sad_pandas', 'happy_cats', 'people']] 

將它們組合成一個單獨的列表,你可以使用

result = [] 
for s in l: 
    result.extend(re.split(r"_(?:f?or|and)_", s)) 
+0

這需要一個額外的步驟來處理任何一組單詞,如果該單詞在字符串的開頭或結尾,這將不起作用。 – Holt

+0

這是不是在OP所述的要求(因此我的類似答案的免責聲明)... +1從我這個答案 –

+0

@霍爾特:對,喬蘭的版本更好的首要考慮。不確定第二個是否有問題。 –

6

你可以使用正則表達式:

from itertools import chain 
import re 

pattern = re.compile(r'_(?:{})_'.format('|'.join([re.escape(w) for w in keywords]))) 

result = list(chain.from_iterable(pattern.split(w) for w in input_list)) 

的模式動態地從您的關鍵字列表中創建。該字符串'happy_hats_for_cats'分割上'_for_'

>>> re.split(r'_for_', 'happy_hats_for_cats') 
['happy_hats', 'cats'] 

,而是因爲我們實際上製作了一套備選方案(使用|元字符),你拆就任何關鍵字:

>>> re.split(r'_(?:for|or|and)_', 'sad_pandas_and_happy_cats_for_people') 
['sad_pandas', 'happy_cats', 'people'] 

每個分割結果給你一個字符串列表(只有一個,如果沒有什麼可以分割);使用itertools.chain.from_iterable()可以讓我們將所有這些列表視爲一個長迭代。

演示:

>>> from itertools import chain 
>>> import re 
>>> keywords = ['for', 'or', 'and'] 
>>> input_list = ['happy_feet', 'happy_hats_for_cats', 'sad_fox_or_mad_banana','sad_pandas_and_happy_cats_for_people'] 
>>> pattern = re.compile(r'_(?:{})_'.format('|'.join([re.escape(w) for w in keywords])))  
>>> list(chain.from_iterable(pattern.split(w) for w in input_list)) 
['happy_feet', 'happy_hats', 'cats', 'sad_fox', 'mad_banana', 'sad_pandas', 'happy_cats', 'people'] 
+0

偉大的思想和所有這一切:P –

+1

@JoranBeasley:這是一個蹩腳的移動網絡,目前:-(在我的火車旅程的前20分鐘(它來來去去)沒有太多的連接。 –

2

這樣做,只使用內置的方法的另一種方式,就是更換什麼用替換字符串中的每個字符串在['for', 'or', 'and']一切發生,例如說_1_(這可能是任意的字符串),則在再結每次迭代的,分裂移到該替換字符串:

l = ['happy_feet', 'happy_hats_for_cats', 'sad_fox_or_mad_banana','sad_pandas_and_happy_cats_for_people'] 
replacement_s = '_1_' 
lookup = ['for', 'or', 'and'] 
lookup = [x.join('_'*2) for x in lookup] #Changing to: ['_for_', '_or_', '_and_'] 
results = [] 
for i,item in enumerate(l): 
    for s in lookup: 
     if s in item: 
      l[i] = l[i].replace(s,'_1_') 
    results.extend(l[i].split('_1_')) 

OUTPUT:

['happy_feet', 'happy_hats', 'cats', 'sad_fox', 'mad_banana', 'sad_pandas', 'happy_cats', 'people']