Почему при разделении пустой строки в Python функция split () возвращает пустой список, а split ('\ n') возвращает ['']?


160

Я использую split('\n')для получения строк в одной строке и обнаружил, что ''.split()возвращает пустой список [], а ''.split('\n')возвращает ['']. Есть ли конкретная причина такой разницы?

А есть ли более удобный способ подсчета строк в строке?


Ответы:


250

Вопрос: я использую split ('\ n') для получения строк в одной строке и обнаружил, что '' .split () возвращает пустой список [], а '' .split ('\ n') возвращает [''] .

Метод str.split () имеет два алгоритма. Если аргументы не указаны, он разбивается на повторяющиеся пробелы. Однако, если указан аргумент, он рассматривается как единственный разделитель без повторных запусков.

В случае разделения пустой строки первый режим (без аргументов) вернет пустой список, потому что пробелы съедены и в список результатов нет значений для добавления.

Напротив, второй режим (с таким аргументом, как \n) создаст первое пустое поле. Представьте, что если бы вы написали '\n'.split('\n'), вы бы получили два поля (одно разделенное, дает вам две половины).

Вопрос: Есть ли конкретная причина такой разницы?

Этот первый режим полезен, когда данные выровнены в столбцы с переменным количеством пробелов. Например:

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

Второй режим полезен для данных с разделителями, таких как CSV, где повторяющиеся запятые обозначают пустые поля. Например:

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

Обратите внимание, количество полей результатов на единицу больше, чем количество разделителей. Подумайте о перерезании веревки. Если вы не сделаете разрезов, у вас будет один кусок. Сделав один разрез, получается две штуки. Сделав два надреза, получается три штуки. То же самое и с методом Python str.split (delimiter) :

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

Вопрос: А есть ли более удобный способ подсчета строк в строке?

Да, есть несколько простых способов. Один использует str.count (), а другой - str.splitlines () . Оба способа дадут одинаковый ответ, если в последней строке не пропущен \n. Если последний символ новой строки отсутствует, подход str.splitlines даст точный ответ. Более быстрый и точный метод использует метод count, но затем исправляет его для последней строки новой строки:

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

Вопрос от @Kaz: какого черта два совершенно разных алгоритма объединены в одну функцию?

Сигнатуре str.split около 20 лет, и ряд API того времени строго прагматичен. Хотя сигнатура метода не идеальна, она не является «ужасной». По большей части выбор дизайна API Гвидо выдержал испытание временем.

Текущий API не лишен преимуществ. Рассмотрим такие строки, как:

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

Когда их просят разбить эти строки на поля, люди склонны описывать их одним и тем же английским словом «split». Когда их просят прочитать код, такой как fields = line.split() или fields = line.split(','), люди склонны правильно интерпретировать утверждения как «разбивает строку на поля».

Инструмент преобразования текста в столбцы Microsoft Excel сделал аналогичный выбор API и объединяет оба алгоритма разделения в одном инструменте. Кажется, что люди мысленно моделируют разделение полей как единую концепцию, даже если задействовано более одного алгоритма.


28

Это , кажется, просто так , как это должно работать, в соответствии с документацией :

Возвращается разделение пустой строки указанным разделителем [''].

Если sep не указан или равен None, применяется другой алгоритм разделения: последовательности последовательных пробелов рассматриваются как один разделитель, и результат не будет содержать пустых строк в начале или в конце, если строка имеет ведущие или завершающие пробелы. Следовательно, разделение пустой строки или строки, состоящей только из пробелов, с разделителем None возвращает [].

Итак, чтобы было понятнее, split()функция реализует два разных алгоритма разделения и использует наличие аргумента, чтобы решить, какой из них запустить. Это может быть связано с тем, что он позволяет оптимизировать не более аргументов, чем тот, который имеет аргументы; Я не знаю.


4

.split()без параметров пытается умничать. Он разбивается на любые пробелы, табуляции, пробелы, переводы строк и т. Д., А также пропускает все пустые строки в результате этого.

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

По сути, .split()без параметров используются для извлечения слов из строки, в отличие от .split()параметров, которые просто берут строку и разбивают ее.

В этом причина разницы.

И да, подсчет строк путем разделения - неэффективный способ. Подсчитайте количество переводов строки и добавьте один, если строка не заканчивается переводом строки.


2

Использование count():

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

4
+ 1 следует использовать только в том случае, если текст не заканчивается на '\ n'.
Леннарт Регебро

8
Ну, если он заканчивается на "\ n", то последняя строка - пустая строка. Хотя бесполезно, но все равно считается линией, не так ли?
Якуб М.

2
нет. когда я пишу 3 строки текста в файл и заканчиваю каждую из них переводом строки, я бы сказал, что файл содержит 3 строки. в unix лучше всего, чтобы текстовый файл всегда заканчивался переводом строки. в противном случае cat fileискажает вашу командную строку и жалуется подрывная деятельность. vi всегда добавляет один.
user829755

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

Обратите внимание на последнее предложение.

Чтобы подсчитать строки, вы можете просто посчитать, сколько \nих:

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

Последняя часть учитывает последнюю строку, которая не заканчивается \n, даже если это означает, что Hello, World!и у Hello, World!\nних одинаковое количество строк (что для меня разумно), в противном случае вы можете просто добавить 1к количеству \n.


0

Чтобы подсчитать строки, вы можете подсчитать количество разрывов строк:

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

Редактировать :

Другой ответ со встроенным countболее подходящим, на самом деле


3
Помимо простого использования count, bools можно добавлять (фактически, они являются подклассом int), поэтому genexp можно записать как sum(s == "\n" for s in the_string).
lvc

Сейчас вы считаете только пустые строки?
Thijs van Dien

Да, я не отбрасываю пустые строчки
Якуб М.
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.