it-swarm.com.ru

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

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

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

129
godice

Вопрос: я использую 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-интерфейсов той эпохи строго прагматичны. Хотя подпись метода и не идеальна, она не "ужасна". По большей части, выбор дизайна Guido 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 и включает оба алгоритма разделения в одном инструменте. Люди, кажется, мысленно моделируют разделение полей как единую концепцию, даже если задействовано более одного алгоритма.

210
Raymond Hettinger

Кажется, это просто способ, которым он должен работать, согласно документация :

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

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

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

28
unwind

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

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

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

Это причина разницы.

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

3
Lennart Regebro

Используйте count():

s = "Line 1\nLine2\nLine3"
n_lines = s.count('\n') + 1
2
Gareth Webber
>>> 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.

1
Bakuriu

Для подсчета строк вы можете подсчитать количество разрывов строк:

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

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

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

0
Jakub M.