2015-12-22 57 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']