Waarom geeft split() bij het splitsen van een lege string in Python een lege lijst terug terwijl split(‘\n’) [”] teruggeeft?

Ik gebruik split('\n')om regels in één string te krijgen, en ontdekte dat ''.split()een lege lijst retourneert, [], terwijl ''.split('\n')['']teruggeeft. Is er een specifieke reden voor een dergelijk verschil?

En is er een handiger manier om regels in een string te tellen?


Antwoord 1, autoriteit 100%

Vraag: ik gebruik split('\n')om regels in één string te krijgen, en ontdekte dat ''.split()een lege lijst retourneert, [], terwijl ''.split('\n')['']teruggeeft.

De str.split()methode heeft twee algoritmen. Als er geen argumenten worden gegeven, wordt het gesplitst bij herhaalde reeksen witruimte. Als er echter een argument wordt gegeven, wordt het behandeld als een enkel scheidingsteken zonder herhaalde runs.

In het geval van het splitsen van een lege string, retourneert de eerste modus (geen argument) een lege lijst omdat de witruimte is opgegeten en er geen waarden zijn om in de resultatenlijst te plaatsen.

Daarentegen zal de tweede modus (met een argument zoals \n) het eerste lege veld produceren. Bedenk dat als u '\n'.split('\n')had geschreven, u twee velden zou krijgen (één splitsing geeft u twee helften).

Vraag: Is er een specifieke reden voor een dergelijk verschil?

Deze eerste modus is handig wanneer gegevens zijn uitgelijnd in kolommen met variabele hoeveelheden witruimte. Bijvoorbeeld:

>>> data = '''\
Shasta      California     14,200
McKinley    Alaska         20,300
Fuji        Japan          12,400
'''
>>> for line in data.splitlines():
        print(line.split())
['Shasta', 'California', '14,200']
['McKinley', 'Alaska', '20,300']
['Fuji', 'Japan', '12,400']

De tweede modus is handig voor gegevens met scheidingstekens, zoals CSVwaarbij herhaalde komma’s leeg zijn velden. Bijvoorbeeld:

>>> data = '''\
Guido,BDFL,,Amsterdam
Barry,FLUFL,,USA
Tim,,,USA
'''
>>> for line in data.splitlines():
        print(line.split(','))
['Guido', 'BDFL', '', 'Amsterdam']
['Barry', 'FLUFL', '', 'USA']
['Tim', '', '', 'USA']

Let op, het aantal resultaatvelden is één groter dan het aantal scheidingstekens. Denk aan het doorknippen van een touw. Als je niet snijdt, heb je één stuk. Een snede maken, geeft twee stukken. Twee sneden maken, geeft drie stukken. En zo is het ook met de str.split(delimiter)methode van Python:

>>> ''.split(',')       # No cuts
['']
>>> ','.split(',')      # One cut
['', '']
>>> ',,'.split(',')     # Two cuts
['', '', '']

Vraag: En is er een handiger manier om regels in een string te tellen?

Ja, er zijn een paar eenvoudige manieren. Men gebruikt str.count()en de andere gebruikt str.splitlines(). Beide manieren geven hetzelfde antwoord, tenzij in de laatste regel de \nontbreekt. Als de laatste nieuwe regel ontbreekt, zal de str.splitlinesbenadering het juiste antwoord geven. Een snellere techniek die ook nauwkeurig is, gebruikt de telmethode, maar corrigeert deze vervolgens voor de laatste nieuwe regel:

>>> data = '''\
Line 1
Line 2
Line 3
Line 4'''
>>> data.count('\n')                               # Inaccurate
3
>>> len(data.splitlines())                         # Accurate, but slow
4
>>> data.count('\n') + (not data.endswith('\n'))   # Accurate and fast
4    

Vraag van @Kaz: Waarom zijn er in godsnaam twee heel verschillende algoritmen in één enkele functie gesmeed?

De handtekening voor str.splitis ongeveer 20 jaar oud en een aantal API’s uit die tijd zijn strikt pragmatisch. Hoewel niet perfect, is de handtekening van de methode ook niet “vreselijk”. Voor het grootste deel hebben Guido’s API-ontwerpkeuzes de tand des tijds doorstaan.

De huidige API is niet zonder voordelen. Overweeg strings zoals:

ps_aux_header  = 'USER               PID  %CPU %MEM      VSZ'
patient_header = 'name,age,height,weight'

Als hen wordt gevraagd deze strings in velden op te splitsen, hebben mensen de neiging om beide te beschrijven met hetzelfde Engelse woord, ‘split’. Wanneer gevraagd wordt om code te lezen zoals fields = line.split()of fields = line.split(','), hebben mensen de neiging om de uitspraken correct te interpreteren als “splits een regel in velden”.

Microsoft Excel’s text-to-columns toolmaakte een vergelijkbare API-keuze en
bevat beide splitsingsalgoritmen in dezelfde tool. Mensen lijken veldsplitsing mentaal te modelleren als een enkel concept, ook al is er meer dan één algoritme bij betrokken.


Antwoord 2, autoriteit 12%

Het lijkt gewoon te zijn zoals het hoort te werken, volgens de documentatie:

Het splitsen van een lege tekenreeks met een opgegeven scheidingsteken levert ['']op.

Als sep niet is opgegeven of Geen is, wordt een ander splitsingsalgoritme toegepast: reeksen opeenvolgende witruimten worden beschouwd als een enkel scheidingsteken en het resultaat bevat geen lege tekenreeksen aan het begin of einde als de tekenreeks een voorloop- of een volgtekenreeks heeft witte ruimte. Bijgevolg levert het splitsen van een lege tekenreeks of een tekenreeks die alleen uit witruimte bestaat met een Geen-scheidingsteken [] op.

Dus, om het duidelijker te maken, implementeert de functie split()twee verschillende splitsingsalgoritmen en gebruikt de aanwezigheid van een argument om te beslissen welke moet worden uitgevoerd. Dit kan zijn omdat het de ene voor geen argumenten meer kan optimaliseren dan die met argumenten; Ik weet het niet.


Antwoord 3, autoriteit 2%

.split()zonder parameters probeert slim te zijn. Het splitst zich op elke witruimte, tabs, spaties, regelfeeds enz., en het slaat ook alle lege tekenreeksen als gevolg hiervan over.

>>> "  fii    fbar \n bopp ".split()
['fii', 'fbar', 'bopp']

In wezen wordt .split()zonder parameters gebruikt om woorden uit een string te extraheren, in tegenstelling tot .split()met parameters die alleen een string nodig hebben en splitsen het.

Dat is de reden voor het verschil.

En ja, regels tellen door te splitsen is geen efficiënte manier. Tel het aantal regelinvoeren en voeg er een toe als de tekenreeks niet eindigt met een regelinvoer.


Antwoord 4

Gebruik count():

s = "Line 1\nLine2\nLine3"
n_lines = s.count('\n') + 1

Antwoord 5

>>> print str.split.__doc__
S.split([sep [,maxsplit]]) -> list of strings
Return a list of the words in the string S, using sep as the
delimiter string.  If maxsplit is given, at most maxsplit
splits are done. If sep is not specified or is None, any
whitespace string is a separator and empty strings are removed
from the result.

Let op de laatste zin.

Om regels te tellen, kun je eenvoudig tellen hoeveel \ner zijn:

line_count = some_string.count('\n') + some_string[-1] != '\n'

Het laatste deel houdt rekening met de laatste regel die niet eindigt met \n, hoewel dit betekent dat Hello, World!en Hello, World!\nhebben dezelfde lijntelling (die voor mij redelijk is), anders kunt u eenvoudig 1toevoegen aan de telling van \n.


Antwoord 6

Om lijnen te tellen, kunt u het aantal lijnonderbrekingen tellen:

n_lines = sum(1 for s in the_string if s == "\n") + 1 # add 1 for last line

bewerken :

Het andere antwoord met ingebouwde countis meer geschikt, eigenlijk

Other episodes