2016-04-10 4 views
4

私はPythonには新しく、問題が残っています。私は、私は2人の間の会話を含む文字列を持っていることをやろうとしている:特定のキーワードがリストに記載された後に文字列をスライスする

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

私は名前としてdylankidと先輩を使用して文字列から2つのリストを作成します:

dylankid = [ ] 
senpai = [ ] 

することとここでは私が苦労している場所dylankidの中で文字列に 'dylankid'の後ろに来るすべての単語を配置したいが、次の 'dylankid'または 'senpai'の前に 同じことがsenpaiリスト のようになりますこの

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

dylankidからのすべてのメッセージを含むdylankidおよびその逆。

私はそれをスライスして、split()re.compile()を使って調べましたが、スライスを開始する場所と停止する場所を指定する方法を理解できません。

がうまくいけば、十分に明確で、任意の助けいただければ幸いた:)キーは人物であると値は、メッセージのリストどこ

+0

[.partition](https://docs.python.org/2/library/stdtypes.html#str.part)があります。 ition)は、指定した区切り文字の後で文字列を分割できるので便利です。 –

+0

ランダムな単語に ':'が付いていますか? –

+0

@PadraicCunninghamはいあります。 –

答えて

4

次のコードは、辞書を作成します。

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*'] 
+0

2つのメモ:1 - 恐らく 're.finditer'は良いでしょう... 2 - あなたのパターンを' pat'、 'pat.finditer'として' re.compile'するのが良いでしょう。 –

+1

@Iron Fist: 're.finditer'は、多くのマッチがある場合にメモリを節約しますが、この特定のシナリオで' re.compile'を使用する動機は何ですか? – niemmi

+0

同じ理由で私は 're.finditer'を使ってパフォーマンスを改善しましたが、OPの関心事ではないようです。 –

1

これは強化することができますが、より多くのユーザー名に拡張するのは簡単です。

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)) 

結果は以下のとおりです。あなたが単語を分割し、GROUPBYを使用することができます

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

__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*']} 

たびに、私たち入手する 私たちの辞書の名前はnext(v)でその名前を使用し、str.joinを使用して次の名前までのグループの次のグループを取得し、1つの文字列に戻って結合します。大きな文字列の

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 
関連する問題