Почему пустые строки возвращаются в результатах split ()? - PullRequest
96 голосов
/ 04 февраля 2010

Какой смысл '/segment/segment/'.split('/') возвращать ['', 'segment', 'segment', '']?

Обратите внимание на пустые элементы. Если вы разбиваете разделитель, который оказывается в первой позиции и в самом конце строки, какое дополнительное значение дает возврат пустой строки с каждого конца?

Ответы [ 6 ]

142 голосов
/ 04 февраля 2010

str.split дополняет str.join, поэтому

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

возвращает вас к исходной строке.

Если бы не было пустых строк, первая и последняя '/' были быпропадать после join()

43 голосов
/ 18 января 2016

В целом, чтобы удалить пустые строки, возвращаемые в результатах split(), вы можете обратиться к функции filter.

Пример:

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

1010 * возвращается *

['segment', 'segment']
27 голосов
/ 04 февраля 2010

Здесь следует рассмотреть два основных момента:

  • Ожидать, что результат '/segment/segment/'.split('/') будет равен ['segment', 'segment'], разумно, но тогда это приводит к потере информации. Если split() работал так, как вы хотели, если я скажу вам, что a.split('/') == ['segment', 'segment'], вы не можете сказать мне, что было a.
  • Каким должен быть результат 'a//b'.split()? ['a', 'b']? Или ['a', '', 'b']? Т.е. следует ли split() объединять смежные разделители? Если это так, тогда будет очень трудно проанализировать данные, которые разделены символом, и некоторые поля могут быть пустыми. Я вполне уверен, что есть много людей, которые do хотят получить пустые значения в результате для указанного выше случая!

В итоге все сводится к двум вещам:

Согласованность: если у меня есть n разделители, в a я получаю n+1 значения после split().

Должна быть возможность делать сложные вещи и легко делать простые вещи: если вы хотите игнорировать пустые строки в результате split(), вы всегда можете сделать:

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

но если вы не хотите игнорировать пустые значения, один должен быть в состоянии.

Язык должен выбрать одно определение split() - слишком много разных вариантов использования, чтобы удовлетворить требования каждого по умолчанию. Я думаю, что выбор Python хорош и наиболее логичен. (Кроме того, одна из причин, по которой мне не нравятся C strtok(), заключается в том, что он объединяет смежные разделители, что делает его чрезвычайно трудным для серьезного анализа / токенизации.)

Есть одно исключение: a.split() без аргумента сжимает последовательные пробелы, но можно утверждать, что это правильно в этом случае. Если вы не хотите поведения, вы всегда можете a.split(' ').

7 голосов
/ 04 февраля 2010

Наличие x.split(y) всегда возвращать список 1 + x.count(y) предметов является драгоценной регулярностью - как уже отмечал @ gnibbler, это делает split и join точные инверсии друг друга (как они, очевидно, должны быть),он также точно отображает семантику всех видов записей, соединенных разделителями (таких как csv строк файла [[за исключением проблем с цитированием]], строк из /etc/group в Unix и т. д.), что позволяет (как @ Roman'sупомянутый ответ) простая проверка (например) абсолютных и относительных путей (в путях к файлам и URL-адресам) и т. д.

Еще один способ взглянуть на это состоит в том, что вы не должны просто выбрасывать информацию из окна.без выгоды.Что можно было бы получить, сделав x.split(y) эквивалентным x.strip(y).split(y)?Ничего, конечно - легко использовать вторую форму, когда вы это имеете в виду, но если первая форма будет произвольно означать вторую, у вас будет много работы, когда вы делаете хотите первый (который, как указывает предыдущий абзац, далеко не редкость).

Но на самом деле мышление с точки зрения математической регулярности - это самый простой и общий способ научить себя создавать сносные API,Чтобы взять другой пример, очень важно, чтобы для любых допустимых x и y x == x[:y] + x[y:] - что сразу указывает, почему один крайний срез должен быть исключен.Чем проще инвариантное утверждение, которое вы можете сформулировать, тем вероятнее, что полученная семантика - это то, что вам нужно в реальной жизни - часть мистического факта, что математика очень полезна при работе со вселенной.

Попробуйте сформулировать инвариант для диалекта split, в котором начальные и конечные разделители имеют специальный регистр ... контрпример: строковые методы, такие как isspace, не максимально просты - x.isspace() isэквивалентно x and all(c in string.whitespace for c in x) - это глупое ведение x and, поэтому вы так часто обнаруживаете, что кодируете not x or x.isspace(), чтобы вернуться к простоте, которую должен быть встроен в строковые методы is... (при этом пустая строка «это» все, что вы хотите - вопреки чувству человека на улице, может быть, [[пустые наборы, такие как ноль и с, всегда смущают большинство людей ;-)]], но полностью соответствуюточевидный, отточенный математический здравый смысл! -).

5 голосов
/ 04 февраля 2010

Ну, это позволяет вам узнать, что там был разделитель.Итак, просмотр 4 результатов позволяет узнать, что у вас было 3 разделителя.Это дает вам возможность делать с этой информацией все, что вы хотите, вместо того, чтобы Python отбрасывал пустые элементы, а затем заставлял вас вручную проверять начальные или конечные разделители, если вам нужно это знать.Скажем, вы хотите проверить абсолютные и относительные имена файлов.Таким образом, вы можете делать все это с разделением, без необходимости проверять, какой первый символ вашего имени файла.

5 голосов
/ 04 февраля 2010

Я не уверен, какой ответ ты ищешь? Вы получаете три матча, потому что у вас есть три разделителя. Если вы не хотите этот пустой, просто используйте:

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