2015-12-22 12 views
7

Ho una lista di stringhe come tale,suddivisione di un testo sulla base di un certo insieme di parole

['happy_feet', 'happy_hats_for_cats', 'sad_fox_or_mad_banana','sad_pandas_and_happy_cats_for_people'] 

Dato un elenco di parole chiave come ['for', 'or', 'and'] voglio essere in grado di analizzare l'elenco in un'altra lista in cui se il elenco di parole chiave si verifica nella stringa, dividere quella stringa in più parti.

Ad esempio, il set di cui sopra sarebbe diviso in

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

Attualmente ho dividere ogni stringa interna da sottolineatura e hanno un ciclo for in cerca di un indice di una parola chiave, poi ricombinare le stringhe sottolineare. C'è un modo più veloce per farlo?

+1

Questo è probabilmente molto veloce. È troppo lento per la tua applicazione? – TigerhawkT3

+0

Non proprio, sono solo un po 'nuovo in Python e non sapevo se esistesse un modo migliore e più conciso per farlo. – SharpObject

+1

Generalmente raccomando di misurare prima di ottimizzare. :) Le operazioni di stringa di base, in particolare, sono spesso più veloci di approcci più complessi, comunque. – TigerhawkT3

risposta

6
>>> pat = re.compile("_(?:%s)_"%"|".join(sorted(split_list,key=len))) 
>>> list(itertools.chain(pat.split(line) for line in data)) 

vi darà l'output desiderato per il dataset di esempio fornito

in realtà con i _ delimitatori si Dont davvero bisogno di ordinarlo per lunghezza in modo da poter fare solo

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

Per combinarli in un unico elenco, è possibile utilizzare

result = [] 
for s in l: 
    result.extend(re.split(r"_(?:f?or|and)_", s)) 
+0

Ciò richiede un ulteriore passaggio per gestire qualsiasi insieme di parole e ciò non funzionerebbe se la parola è all'inizio o alla fine della stringa. – Holt

+0

che non era nei requisiti stabiliti da OP (da cui la dichiarazione di non responsabilità sulla mia risposta simile) ... +1 a questa risposta da me –

+0

@Holt: Giusto, la versione di Joran è migliore al primo riguardo. Non sono sicuro se il secondo è un problema. –

6

si potrebbe usare un'espressione regolare:

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

Il modello viene creato dinamicamente dal tuo elenco di parole chiave. La stringa 'happy_hats_for_cats' è diviso su '_for_':

>>> re.split(r'_for_', 'happy_hats_for_cats') 
['happy_hats', 'cats'] 

ma perché abbiamo effettivamente prodotto una serie di alternative (utilizzando il | metacarattere) si arriva a dividere su una delle parole chiave:

>>> re.split(r'_(?:for|or|and)_', 'sad_pandas_and_happy_cats_for_people') 
['sad_pandas', 'happy_cats', 'people'] 

Ogni risultato scissione ti dà una lista di stringhe (una sola se non c'era nulla da dividere); usando itertools.chain.from_iterable() possiamo trattare tutte queste liste come una lunga iterabile.

Demo:

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

grandi menti e tutto questo: P –

+1

@JoranBeasley: questo è su una rete mobile schifosa al momento Triste Non molta connettività per i primi 20 minuti del mio viaggio in treno (va e viene). –

2

Un altro modo di fare questo, utilizzando solo il metodo built-in, è quello di sostituire tutte le occorrenze di ciò che è in ['for', 'or', 'and'] in ogni stringa con una stringa di sostituzione, diciamo per esempio _1_ (potrebbe essere qualsiasi stringa), poi a poi fine di ogni iterazione, ad suddiviso su questa stringa di sostituzione:

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