2011-01-03 13 views
22

Python ha un build-in (nel senso delle librerie standard) per eseguire una divisione su stringhe che produce un iteratore piuttosto che un elenco? Ho in mente di lavorare su stringhe molto lunghe e di non dover consumare la maggior parte della stringa.Divisione di una stringa in un iteratore

+2

"non è necessario consumare la maggior parte della stringa"? Cosa significa questo? L'oggetto stringa è tutto in memoria, giusto? Dato che è tutto in memoria, ed è già una sequenza, non c'è nulla di necessario per iterare sui personaggi. Puoi definire cosa intendi per "non è necessario consumare la maggior parte della stringa"? –

+0

Sì, la stringa è già in memoria. Ma non ho bisogno di attraversare l'intera stringa per capire dove dividere o creare le sottostringhe risultanti dalla divisione. –

+1

Forse hai bisogno di un tokeniser o scanner di qualche tipo che fornisce un iteratore. La risposta qui sotto con la soluzione di espressione regolare potrebbe funzionare. –

risposta

15

Non dividere direttamente le stringhe in quanto tali, ma il modulo re ha re.finditer() (e il corrispondente metodo finditer() su qualsiasi espressione regolare compilata).

@Zero chiesto un esempio:

>>> import re 
>>> s = "The quick brown\nfox" 
>>> for m in re.finditer('\S+', s): 
...  print(m.span(), m.group(0)) 
... 
(0, 3) The 
(4, 9) quick 
(13, 18) brown 
(19, 22) fox 
+2

Un esempio di come usare 're.finditer()' per iterare le stringhe divise sarebbe utile. – Zero

+1

@Zero, non esattamente difficile, ma ecco qua. – Duncan

5

come S. Lott, non si sa bene ciò che si desidera. Ecco il codice che può aiutare:

s = "This is a string." 
for character in s: 
    print character 
for word in s.split(' '): 
    print word 

Ci sono anche s.index() e s.find() per trovare il carattere successivo.


tardi: Va bene, qualcosa di simile.

>>> def tokenizer(s, c): 
...  i = 0 
...  while True: 
...   try: 
...    j = s.index(c, i) 
...   except ValueError: 
...    yield s[i:] 
...    return 
...   yield s[i:j] 
...   i = j + 1 
... 
>>> for w in tokenizer(s, ' '): 
...  print w 
... 
This 
is 
a 
string. 
+1

Vedere i chiarimenti nei commenti. Questo non risponde alla domanda. – marcog

+0

Chiede esplicitamente anche un * built-in * –

+3

@ 7vies: ho pensato che fosse meglio che dire "No" o "Usare le espressioni regolari (ad esempio la risposta sopra)". – hughdbrown

0

Si potrebbe usare qualcosa di simile SPARK (che è stato assorbito nella distribuzione di Python per sé, anche se non importabile dalla libreria standard), ma alla fine usa le espressioni regolari e in modo Duncan's answer sarebbe forse servire altrettanto bene se fosse facile come "dividere in spazi".

L'altra opzione, molto più ardua, sarebbe quella di scrivere il proprio modulo Python in C per farlo, se si desidera realmente la velocità, ma è ovviamente un investimento molto più lungo.

3

Se non è necessario consumare l'intera stringa, è perché si sta cercando qualcosa di specifico, giusto? Quindi cerca quello, con re o .find() invece di dividere. In questo modo puoi trovare la parte della stringa che ti interessa e dividerla.

+0

Nell'applicazione che avevo in mente, volevo dividere lo spazio bianco, controllare la terza sottostringa, a seconda di cosa fosse, controllare la quarta o sesta sottostringa e quindi eventualmente elaborare il resto della stringa. –

+2

@ metafora pitonica: Sì, se quella stringa è * veramente * lunga potresti voler usare 're' o' find'. Nell'altro caso, basta dividerlo in spazi vuoti. Non lo so, ma per me la tua domanda sembra essere un'ottimizzazione prematura. ;) Quindi devi profilarlo per essere sicuro. –

+3

@ metafora pitonica: per il testo normale si tratta solo dell'ottimizzazione prematura. Il testo inizia ad essere "grande" da qualche parte >> 10 MB. Per l'applicazione che hai descritto, andrei con 'text.split (None, 6)' per ottenere le prime 6 parole. Se devi dividere l'intero testo, fallo subito. –

0

Vedere itertools. Contiene cose come takewhile, islice e groupby che ti consentono di suddividere un iterabile (una stringa è iterabile) in un altro iterabile basato su indici o condizioni di tipo booleane.

0

Non esiste un analogico basato su iteratore incorporato di str.split. A seconda delle esigenze si potrebbe fare una lista iteratore:

iterator = iter("abcdcba".split("b")) 
iterator 
# <list_iterator at 0x49159b0> 
next(iterator) 
# 'a' 

Tuttavia, uno strumento da questa libreria di terze parti probabilmente offre ciò che si vuole, more_itertools.split_at. Vedi anche this post per un esempio.

Problemi correlati