Perché vengono restituite stringhe vuote nei risultati di split ()?


120

Qual è il punto di '/segment/segment/'.split('/')tornare ['', 'segment', 'segment', '']?

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


1
Ho la stessa domanda e l'ho cercata a lungo. Ora capisco che i risultati vuoti sono davvero importanti. Grazie per la tua domanda.
emeraldhieu

2
Una soluzione è quella di strip()'/segment/segment/'.strip('/').split('/')
rimuovere i

Risposte:


178

str.splitcomplementi str.join, quindi

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

ti riporta la stringa originale.

Se le stringhe vuote non fossero presenti, la prima e l'ultima '/'sarebbero mancanti dopojoin()


11
Semplice, ma risponde pienamente alla domanda.
orokusaki

Sono rimasto scioccato nello scoprire che le virgolette ricci sono effettivamente valide in Python ... ma, ma ... come? I documenti non sembrano menzionarlo.
Tim Pietzcker

@Tim, non ho idea di come siano finite quelle citazioni: /
John La Rooy

7
Quindi, non stai usando Microsoft Word come IDE Python, allora? :)
Tim Pietzcker

1
@ aaa90210 chi ha detto che le risposte semplici non erano le migliori? Era un commento (in primo luogo, 5 anni fa) su come la risposta fosse semplice, ma rispondesse pienamente alla domanda. Usare "ma" in una frase non implica niente di male. Una risposta non semplice avrebbe potuto essere una risposta più completa (ad esempio, comprese le decisioni pertinenti o una PEP relativa alla funzionalità annotata).
orokusaki

88

Più in generale, per rimuovere le stringhe vuote restituite nei split()risultati, potresti voler esaminare la filterfunzione.

Esempio:

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

ritorna

['segment', 'segment']

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

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

29

Ci sono due punti principali da considerare qui:

  • Aspettarsi che il risultato di '/segment/segment/'.split('/')essere uguale a ['segment', 'segment']è ragionevole, ma in questo caso si perdono informazioni. Se ha split()funzionato come volevi, se ti dico questo a.split('/') == ['segment', 'segment'], non puoi dirmi cosa aera.
  • Quale dovrebbe essere il risultato di 'a//b'.split()essere? ['a', 'b']?, o ['a', '', 'b']? Vale a dire, dovresti split()unire delimitatori adiacenti? In tal caso, sarà molto difficile analizzare i dati delimitati da un carattere e alcuni campi possono essere vuoti. Sono abbastanza sicuro che ci sono molte persone che fanno sì che i valori vuoti nel risultato per il caso di cui sopra!

Alla fine, si riduce a due cose:

Coerenza: se ho ndelimitatori, in a, ottengo i n+1valori dopo il split().

Dovrebbe essere possibile fare cose complesse e facili cose semplici: se vuoi ignorare le stringhe vuote come risultato di split(), puoi sempre fare:

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

ma se uno non vuole ignorare i valori vuoti, dovrebbe essere in grado di farlo.

La lingua deve scegliere una definizione di: ci split()sono troppi casi d'uso diversi per soddisfare i requisiti predefiniti di tutti. Penso che la scelta di Python sia buona ed è la più logica. (Per inciso, uno dei motivi per cui non mi piacciono i C strtok()è perché unisce delimitatori adiacenti, rendendo estremamente difficile eseguire un'analisi / tokenizzazione seria con esso.)

C'è un'eccezione: a.split()senza un argomento comprime spazi bianchi consecutivi, ma si può sostenere che questa è la cosa giusta da fare in quel caso. Se non vuoi il comportamento, puoi sempre farlo a.split(' ').


Per coloro che si chiedono se sia più veloce eseguire il nuke di spazi duplicati, quindi dividere o dividere e prendere solo stringhe non vuote, ecco cosa ottengo: python3 -m timeit "import re ; re.sub(' +', ' foo bar baz ', '').split(' ')"-> 875 nsec per ciclo; python3 -m timeit "[token for token in ' foo bar baz '.split(' ') if token]"-> 616 nsec per loop
s3cur3

8

Avere x.split(y)sempre restituire un elenco di 1 + x.count(y)elementi è una preziosa regolarità - come @ gnibbler sta già sottolineato rende splite joininverse esatte della vicenda (come, ovviamente, dovrebbero essere), ma anche le mappe con precisione la semantica di tutti i tipi di record delimitatore incollati ( come csvle righe di file [[al netto dei problemi di citazione]], le righe di /etc/groupUnix e così via), consente (come menzionato nella risposta di @ Roman) facili controlli per (ad esempio) percorsi assoluti e relativi (nei percorsi dei file e negli URL), e così via.

Un altro modo per vederlo è che non dovresti lanciare volutamente informazioni fuori dalla finestra per nessun guadagno. Cosa si guadagnerebbe nel renderlo x.split(y)equivalente a x.strip(y).split(y)? Nulla, ovviamente - è facile da usare la seconda forma in cui questo è quello che vuoi dire, ma se il primo modulo è stato arbitrariamente considerato significare la seconda, che avresti avuto molto lavoro da fare quando si fa desidera che il primo ( che è tutt'altro che raro, come sottolinea il paragrafo precedente).

Ma in realtà, pensare in termini di regolarità matematica è il modo più semplice e generale in cui puoi insegnare a te stesso a progettare API passabili. Per fare un esempio diverso, è molto importante che per ogni valido xe y x == x[:y] + x[y:]- che indica immediatamente perché un estremo di un'affettatura dovrebbe essere escluso. Più semplice è l'asserzione invariante 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 a formulare l'invariante per un splitdialetto in cui i delimitatori iniziali e finali sono in maiuscolo speciale ... controesempio: metodi di stringa come isspacenon sono massimamente semplici - x.isspace()è equivalente a x and all(c in string.whitespace for c in x)- quello stupido inizio x andè il motivo per cui ti trovi così spesso a scrivere codice not x or x.isspace(), per tornare alla semplicità che avrebbe dovuto essere progettata nei is...metodi delle stringhe (per cui una stringa vuota "è" qualsiasi cosa tu voglia - contrariamente al senso del cavallo dell'uomo-in-strada, forse [[insiemi vuoti, come zero & c, hanno sempre confuso la maggior parte delle persone ;-)]], ma in piena conformità al buon senso matematico evidente e ben raffinato ! -).


5

Non sono sicuro che tipo di risposta stai cercando? Ottieni tre corrispondenze perché hai tre delimitatori. Se non vuoi quello vuoto, usa semplicemente:

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

4
-1 perché ottieni quattro corrispondenze non tre, e anche questo non risponde veramente alla domanda.
Roman

1
+1 per contrastare il negativo. Non ha detto che avresti ottenuto tre risultati indietro. Ha detto "tre corrispondenze" per "tre delimitatori", il che mi sembra logico. Tuttavia, non ottieni "quattro corrispondenze" di nulla. Tuttavia, nel risultato vengono restituiti "quattro elementi". Inoltre, non risponde direttamente al "perché", ma fornisce un modo semplice per ottenere ciò che vuole veramente ... che non credo meriti un voto negativo. Se hai intenzione di fare il pelo a qualcuno (con un voto negativo, niente di meno), fai più attenzione! Saluti! 8 ^)
kodybrown

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

Adoro la tua soluzione: rimuovi e dividi per rimuovere il risultato vuoto
Nam G VU

5

Bene, ti fa sapere che c'era un delimitatore lì. Quindi, vedere 4 risultati ti fa sapere che avevi 3 delimitatori. Questo ti dà il potere di fare quello che vuoi con queste informazioni, piuttosto che far cadere gli elementi vuoti da Python e quindi farti controllare manualmente i delimitatori iniziali o finali se ne hai bisogno.

Semplice esempio: supponi di voler controllare i nomi di file assoluti e relativi. In questo modo puoi fare tutto con la divisione, senza dover anche controllare qual è il primo carattere del nome del tuo file.


1

Considera questo esempio minimo:

>>> '/'.split('/')
['', '']

splitdeve darti cosa c'è prima e dopo il delimitatore '/', ma non ci sono altri caratteri. Quindi deve darti la stringa vuota, che tecnicamente precede e segue il '/', perché '' + '/' + '' == '/'.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.