【问题标题】:Slicing a String after certain key words are mentioned into a list在将某些关键字提到列表后将字符串切片
【发布时间】:2016-04-10 13:39:45
【问题描述】:

我是 python 新手,遇到了一个问题。我正在尝试做的是我有一个包含两个人之间对话的字符串:

str = "  dylankid: *random words* senpai: *random words* dylankid: *random words* senpai: *random words*"

我想使用 dylankid 和 senpai 作为名称从字符串中创建 2 个列表:

dylankid = [ ]
senpai = [ ]

这是我苦苦挣扎的地方,在列表 dylankid 中,我想将字符串中 'dylankid' 之后但在下一个 'dylankid' 或 'senpai' 之前的所有单词 前辈名单也是如此 所以它看起来像这样

dylankid = ["random words", "random words", "random words"]
senpai = ["random words", "random words", "random words"]    

dylankid 包含来自 dylankid 的所有消息,反之亦然。

我已经研究过对其进行切片并使用split()re.compile(),但我无法找到一种方法来指定要开始切片以及在哪里停止。

希望它足够清楚,任何帮助将不胜感激:)

【问题讨论】:

  • 您可能会发现.partition 函数很有用,因为它可以在您指定的分隔符之后拆分字符串。
  • 里面有:的随机词吗?
  • @PadraicCunningham 是的,有
  • 对不起,name:
  • @padraicCunningham 不,没有

标签: python string list


【解决方案1】:

以下代码将创建一个字典,其中键是人,值是消息列表:

from collections import defaultdict
import re

PATTERN = '''
    \s*                         # Any amount of space
    (dylankid|senpai)           # Capture person
    :\s                         # Colon and single space
    (.*?)                       # Capture everything, non-greedy
    (?=\sdylankid:|\ssenpai:|$) # Until we find following person or end of string
'''
s = "  dylankid: *random words* senpai: *random words* dylankid: *random words* senpai: *random words*"
res = defaultdict(list)
for person, message in re.findall(PATTERN, s, re.VERBOSE):
    res[person].append(message)

print res['dylankid']
print res['senpai']

它将产生以下输出:

['*random words*', '*random words*']
['*random words*', '*random words*']

【讨论】:

  • 两个注意事项:1-可能re.finditer 会更好... 2-最好将re.compile 改成pat 然后pat.finditer
  • @Iron Fist: re.finditer 会节省内存,以防有很多匹配项,但在这种特殊情况下使用 re.compile 的动机是什么?
  • 出于同样的原因,我会使用re.finditer...性能改进,但我想这似乎不是 OP 的兴趣。
  • @Iron Fist:re.compile 将如何提高这里的性能? Python docs 状态如下:“当表达式将在单个程序中多次使用时,保存生成的正则表达式对象以供重用更有效”。但在这种情况下,只有一个表达式,并且只使用一次。
【解决方案2】:

您可以使用groupby,使用__contains__分割单词和分组

s = "dylankid: *random words d* senpai: *random words s* dylankid: *random words d*  senpai: *random words s*"
from itertools import groupby

d = {"dylankid:": [], "senpai:":[]}

grps = groupby(s.split(" "), d.__contains__)

for k, v in grps:
    if k:
        d[next(v)].append(" ".join(next(grps)[1]))
print(d)

输出:

{'dylankid:': ['*random words d*', '*random words d*'], 'senpai:': ['*random words s*', '*random words s*']}

每次我们在 dict 中获得一个名称时,我们都会将该名称与 next(v) 一起使用,它们会使用 str.join 获取下一组单词直到下一个名称,以连接回单个字符串。

如果你的名字后面没有单词,你可以使用空列表作为下次调用的默认值:

s = "dylankid: *random words d* senpai: *random words s* dylankid: *random words d*  senpai: *random words s* senpai:"
from itertools import groupby

d = {"dylankid:": [], "senpai:":[]}
grps = groupby(s.split(" "), d.__contains__)

for k, v in grps:
    if k:
        d[next(v)].append(" ".join(next(grps,[[], []])[1]))
print(d)

较大字符串的一些计时:

In [15]: dy, sn = "dylankid:", " senpai:"

In [16]: t = " foo " * 1000

In [17]: s = "".join([dy + t + sn + t for _ in range(1000)])

In [18]: %%timeit
   ....: d = {"dylankid:": [], "senpai:": []}
   ....: grps = groupby(s.split(" "), d.__contains__)
   ....: for k, v in grps:
   ....:     if k:
   ....:         d[next(v)].append(" ".join(next(grps, [[], []])[1]))
   ....: 
1 loop, best of 3: 376 ms per loop

In [19]: %%timeit
   ....: PATTERN = '''
   ....:     \s*                         # Any amount of space
   ....:     (dylankid|senpai)           # Capture person
   ....:     :\s                         # Colon and single space
   ....:     (.*?)                       # Capture everything, non-greedy
   ....:     (?=\sdylankid:|\ssenpai:|$) # Until we find following person or end of string
   ....: '''
   ....: res = defaultdict(list)
   ....: for person, message in re.findall(PATTERN, s, re.VERBOSE):
   ....:     res[person].append(message)
   ....: 
1 loop, best of 3: 753 ms per loop

两者都返回相同的输出:

In [20]: d = {"dylankid:": [], "senpai:": []}

In [21]: grps = groupby(s.split(" "), d.__contains__)

In [22]: for k, v in grps:
           if k:                                        
                d[next(v)].append(" ".join(next(grps, [[], []])[1]))
   ....:         

In [23]: PATTERN = '''
   ....:     \s*                         # Any amount of space
   ....:     (dylankid|senpai)           # Capture person
   ....:     :\s                         # Colon and single space
   ....:     (.*?)                       # Capture everything, non-greedy
   ....:     (?=\sdylankid:|\ssenpai:|$) # Until we find following person or end of string
   ....: '''

In [24]: res = defaultdict(list)

In [25]: for person, message in re.findall(PATTERN, s, re.VERBOSE):
   ....:         res[person].append(message)
   ....:     

In [26]: d["dylankid:"] == res["dylankid"]
Out[26]: True

In [27]: d["senpai:"] == res["senpai"]
Out[27]: True

【讨论】:

    【解决方案3】:

    这可以收紧,但应该很容易扩展到更多用户名。

    from collections import defaultdict
    
    # Input string
    all_messages = "  dylankid: *random words* senpai: *random words* dylankid: *random words* senpai: *random words*"
    
    # Expected users
    users = ['dylankid', 'senpai']
    
    starts = {'{}:'.format(x) for x in users}
    D = defaultdict(list)
    results = defaultdict(list)
    
    # Read through the words in the input string, collecting the ones that follow a user name
    current_user = None
    for word in all_messages.split(' '):
        if word in starts:
            current_user = word[:-1]
            D[current_user].append([])
        elif current_user:
            D[current_user][-1].append(word)
    
    # Join the collected words into messages
    for user, all_parts in D.items():
        for part in all_parts:
            results[user].append(' '.join(part))
    

    结果是:

    defaultdict(
        <class 'list'>,
        {'senpai': ['*random words*', '*random words*'],
        'dylankid': ['*random words*', '*random words*']}
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-31
      • 1970-01-01
      • 2021-03-02
      • 2022-01-21
      • 2016-05-01
      • 2013-11-03
      相关资源
      最近更新 更多