2016-04-10 4 views
4

Ich bin neu in Python und ich bin mit einem Problem stecken. Was ich versuche, ein Gespräch zwischen zwei Menschen zu tun, dass ich eine Zeichenfolge haben enthalten:Slicing eine Zeichenfolge nach bestimmten Schlüsselwörtern sind in einer Liste erwähnt

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

I 2 Listen aus dem String mit dylankid und senpai als Namen erstellen möchten:

dylankid = [ ] 
senpai = [ ] 

und Hier ist, wo ich kämpfe, in der Liste dylankid Ich möchte alle Wörter, die nach 'dylankid' in der Zeichenfolge, aber vor dem nächsten 'dylankid' oder 'senpai' setzen, das gleiche gilt für senpai Liste so würde es etwa aussehen diese

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

dylankid enthält alle Nachrichten von dylankid und umgekehrt.

Ich habe es in Schneiden und mit split() und re.compile() untersucht, aber ich kann nicht herausfinden, eine Möglichkeit, um zu beginnen waren zu schneiden und wo zu stoppen.

Hoffentlich war es klar genug, würde jede Hilfe dankbar sein :)

+0

Sie können die [.partition] finden (https://docs.python.org/2/library/stdtypes.html#str.part ition) -Funktion nützlich, da sie Strings nach einem von Ihnen angegebenen Trennzeichen trennen kann. –

+0

Gibt es zufällige Wörter mit ':' in ihnen? –

+0

@PadraicCunningham Ja, es gibt –

Antwort

4

folgenden Code ein dict schaffen, wo Schlüssel sind Personen und Werte Liste der Nachrichten:

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

Es wird folgende Ausgabe :

+0

Zwei Anmerkungen: 1-Wahrscheinlich 're.finditer' wäre besser ... 2-Besser,' re.repipe' dein Muster als 'pat' dann' pat.finditer' statt. –

+1

@Iron Fist: 're.finditer' würde Speicher sparen für den Fall, dass es viele Übereinstimmungen gibt, aber was wäre die Motivation,' re.compile' in diesem speziellen Szenario zu verwenden? – niemmi

+0

aus dem gleichen Grund würde ich 're.finditer' ... Leistungsverbesserung verwenden, aber ich denke, das scheint nicht OPs Interesse zu sein. –

1

Dies kann verschärft werden, aber es sollte einfach sein, um mehr Benutzernamen zu erweitern.

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

Die Ergebnisse sind:

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

Sie einen groupby verwenden können, Wörter getrennt werden und __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) 

Ausgabe mit Gruppierung:

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

Jedes Mal, wenn wir einen bekommen Name in unserem dict verwenden wir diesen Namen mit next(v) sie erhalten die nächste Gruppierung von Wörtern bis zum nächsten Namen mit str.join, um wieder zu einer einzigen Zeichenfolge beizutreten.

Wenn Sie keine Worte nach einem Namen zu haben, passiert ist, können Sie leere Listen als Standardwert für den nächsten Aufruf verwenden:

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) 

Einige Timings auf größeren Strings:

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 

Both retuurn die gleiche Ausgabe:

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 
Verwandte Themen