2010-02-04 15 views
75

Qual è il punto di '/segment/segment/'.split('/') che restituisce ['', 'segment', 'segment', '']?Perché le stringhe vuote vengono restituite nei risultati split()?

Notare gli elementi vuoti. Se stai dividendo su un delimitatore che si trova nella posizione 1 e alla fine di una stringa, quale valore extra ti dà di avere la stringa vuota restituita da ciascuna estremità?

+1

Ho la stessa domanda e cercato per lungo tempo. Ora capisco che i risultati vuoti sono davvero importanti. Grazie per la tua domanda. – Emerald214

+1

Una soluzione è usare 'strip()' per rimuovere i caratteri di divisione e di coda della stringa prima della divisione: ''/ segment/segment /'. Strip ('/'). Split ('/')' – pkamb

risposta

114

str.split complementi str.join, così

"/".join(['', 'segment', 'segment', '']) 

si ottiene indietro la stringa originale.

Se le stringhe vuote non ci fossero, il primo e l'ultimo '/' sarebbero dispersi dopo il join()

+7

Semplice, ma risponde completamente alla domanda. – orokusaki

+0

Sono rimasto scioccato nello scoprire che le virgolette inglesi sono effettivamente valide in Python ... ma, ma ... come? [I documenti] (http://docs.python.org/reference/lexical_analysis.html#string-literals) non sembrano menzionarlo. –

+0

@Tim, non ho idea di come siano arrivate quelle citazioni:/ –

6

Non sono sicuro del tipo di risposta che stai cercando? Ottieni tre corrispondenze perché hai tre delimitatori. Se non si desidera che un vuoto, basta usare:

'/segment/segment/'.strip('/').split('/') 
+3

-1 perché ottieni quattro incontri non tre, e anche questo non risponde alla domanda. – Roman

+0

+1 per neutralizzare il neg. Non ha detto che avresti ottenuto tre risultati. Ha detto "tre fiammiferi" per "tre delimitatori", che mi sembra logico. Tuttavia, non ottieni "quattro fiammiferi" di nulla. Si ottengono "quattro elementi" restituiti nel risultato, però. Inoltre, non risponde direttamente al "perché", ma fornisce un modo semplice per ottenere quello che vuole veramente ... il che non credo meriti un downvote. Se hai intenzione di fare il pisolino qualcuno (con un downvote, non di meno) ti preghiamo di essere più attento! Saluti! 8 ^) – wasatchwizard

+0

@wasatchwizard Grazie per il chiarimento. Apprezzo la correzione e la raccomandazione. Purtroppo, ora il mio voto è bloccato e non può essere modificato. – Roman

5

Beh, consente di sapere c'era un delimitatore lì. Quindi, vedere 4 risultati ti consente di sapere che hai 3 delimitatori. Questo ti dà il potere di fare ciò che vuoi con queste informazioni, piuttosto che avere Python rilascia gli elementi vuoti, e poi farti controllare manualmente l'inizio o la fine dei delimitatori se devi saperlo.

Esempio semplice: si supponga di voler controllare i nomi dei file assoluti o relativi. In questo modo puoi fare tutto con la divisione, senza dover controllare anche quale sia il primo carattere del tuo nome.

+0

+1, grazie amico. – orokusaki

24

Ci sono due punti principali da considerare qui:

  • aspettavo il risultato di '/segment/segment/'.split('/') essere pari a ['segment', 'segment'] è ragionevole, ma allora questo perde informazioni. Se split() ha funzionato come volevi, se ti dico che è a.split('/') == ['segment', 'segment'], non puoi dirmi che cosa era a.
  • Quale dovrebbe essere il risultato di 'a//b'.split() essere? ['a', 'b']? O ['a', '', 'b']? I.e, dovrebbe split() unire i delimitatori adiacenti? Se dovesse essere così, sarà molto difficile analizzare i dati delimitati da un personaggio, e alcuni campi potrebbero essere vuoti. Sono abbastanza sicuro che ci sono molte persone che do vogliono i valori vuoti nel risultato per il caso precedente!

Alla fine, tutto si riduce a due cose:

Consistenza: se ho n delimitatori, in a, ottengo n+1 valori indietro dopo la split().

Dovrebbe essere possibile fare cose complesse, e facile da fare le cose semplici: se si desidera ignorare le stringhe vuote a causa della split(), si può sempre fare:

def mysplit(s, delim=None): 
    return [x for x in s.split(delim) if x] 

ma se uno doesn 't voglio ignorare i valori vuoti, uno dovrebbe essere in grado di.

Il linguaggio deve scegliere una definizione di split() — ci sono troppi casi d'uso diversi per soddisfare il requisito di tutti come predefinito. Penso che la scelta di Python sia buona, ed è la più logica. (Per inciso, uno dei motivi che non mi piacciono di C strtok() è perché si fonde delimitatori adiacenti, rendendo estremamente difficile fare gravi parsing/tokenizzazione con esso.)

C'è una sola eccezione: a.split() senza un argomento stringe lo spazio bianco consecutivo, ma si può sostenere che questa è la cosa giusta da fare in quel caso. Se non vuoi il comportamento, puoi sempre a a.split(' ').

+2

+1, grazie per il dettaglio. – orokusaki

7

Avere x.split(y) tornare sempre un elenco di 1 + x.count(y) elementi è un prezioso regolarità - come @ gnibbler sta già sottolineato rende split e join inverse esatte di ogni altro (come ovviamente dovrebbero essere), ma anche le mappe con precisione la semantica di tutti i tipi di record aggiunti al delimitatore (come le righe di file csv [[net of quoting issues]], righe da /etc/group in Unix e così via), consente (come la risposta di @ Roman menzionata) controlli semplici per (es.) assoluto vs percorsi relativi (in percorsi di file e URL) e così via.

Un altro modo di guardarlo è che non dovresti buttare le informazioni fuori dalla finestra senza alcun guadagno. Cosa si otterrebbe nel rendere x.split(y) equivalente a x.strip(y).split(y)? Niente, ovviamente - è facile usare il secondo modulo quando è quello che intendi, ma se il primo modulo fosse arbitrariamente ritenuto il secondo, avresti molto lavoro da fare quando fai il do vuoi il primo uno (che è tutt'altro che raro, come sottolinea il paragrafo precedente).

Ma in realtà, pensare in termini di regolarità matematica è il modo più semplice e generico per insegnare a progettare API passabili. Per fare un esempio diverso, è molto importante che sia valido per qualsiasi x e x == x[:y] + x[y:] - che indica immediatamente il motivo per cui un estremo di un'affettatura deve essere escluso per. Più semplice è l'asserzione invariabile che puoi formulare, più è probabile che la semantica risultante sia ciò di cui hai bisogno negli usi della vita reale - parte del fatto mistico che la matematica è molto utile nel trattare con l'universo.

Prova formulare l'invariante per un split dialetto in cui iniziali e finali delimitatori sono speciali con involucro ... contro-esempio: metodi delle stringhe come isspace non sono al massimo semplici - x.isspace() equivale a x and all(c in string.whitespace for c in x) - che stupido leader x and è il motivo per cui spesso ti ritrovi a codificare not x or x.isspace(), per tornare alla semplicità con cui deve essere nei metodi di stringa is... (in cui una stringa vuota "è" tutto ciò che vuoi, contrariamente a man-in-the- senso del cavallo di strada, forse [[insiemi vuoti, come zero & c, hanno sempre confuso la maggior parte delle persone ;-)]], ma completamente conforme all'ovvia raffinata matematica ematical buonsenso! -).

+0

+1 per spiegazione dettagliata. Grazie Alex. – orokusaki

16

Più in generale, per rimuovere le stringhe vuote restituite nei risultati split(), è possibile che si desideri esaminare la funzione filter.

Esempio:

filter(None, '/segment/segment/'.split('/')) 

rendimenti

['segment', 'segment'] 
+1

Grazie per questo, non so perché questa risposta sia così in basso, tutto il resto è roba rudimentale. – Wedge

+0

Se si desidera raccogliere il risultato in un elenco invece di ottenere un oggetto filtro come output, inserire l'intera struttura del filtro in 'list (...)'. –

Problemi correlati