【问题标题】:Splitting a string based on a certain set of words根据一组单词拆分字符串
【发布时间】:2015-12-22 07:15:17
【问题描述】:

我有一个这样的字符串列表,

['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 循环查找关键字的索引,然后通过下划线重新组合字符串。有没有更快的方法来做到这一点?

【问题讨论】:

  • 这实际上可能相当快。您的应用程序是否太慢了?
  • 不是真的,我只是对 Python 有点陌生,不知道是否有更好、更简洁的方法。
  • 我通常建议在优化之前测量。 :) 无论如何,基本的字符串操作通常比更复杂的方法更快。
  • 在python中过早优化可能是万恶之源......如果你这样做的方式“足够快”并且对你来说足够清晰......你应该坚持下去:P
  • 感谢所有帮助,我想出了一种正则表达式方式,但我对正则表达式还不够熟悉,无法正确实现它,我会阅读正则表达式代码以更好地帮助我的理解!

标签: python regex string


【解决方案1】:
>>> 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))

【讨论】:

    【解决方案2】:
    >>> [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))
    

    【讨论】:

    • 这需要一个额外的步骤来处理任何一组单词,如果单词在字符串的开头或结尾,这将不起作用。
    • 这不在 OP 规定的要求中(因此我的类似答案中的免责声明)... +1 对我的这个答案
    • @Holt:没错,Joran 的版本在第一方面更好。不确定第二个是否有问题。
    【解决方案3】:

    你可以使用正则表达式:

    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']
    

    【讨论】:

    • @JoranBeasley:这个人目前在一个糟糕的移动网络上 :-( 在我的火车旅程的前 20 分钟内没有太多连接(它来来去去)。
    【解决方案4】:

    另一种仅使用内置方法的方法是用替换字符串替换每个字符串中['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_'))
    

    输出:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-26
      • 2018-06-07
      • 2011-01-16
      • 1970-01-01
      • 1970-01-01
      • 2020-07-18
      • 2011-10-23
      • 1970-01-01
      相关资源
      最近更新 更多