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

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

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

Ответ 1

Вопрос: Я использую 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(разделитель):

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

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

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

>>> 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 Guido выдержал испытание временем.

Существующий API не имеет никаких преимуществ. Рассмотрим строки, такие как:

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

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

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

Ответ 2

Похоже, что он должен работать, согласно документации:

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

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

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

Ответ 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.

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

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

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

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

Ответ 6

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

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

Edit

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