Почему пустые строки возвращаются в результатах split()?

В чем смысл '/segment/segment/'.split('/') возврата ['', 'segment', 'segment', '']?

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

Ответ 1

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

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

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

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

Ответ 2

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

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

В конце концов, это сводится к двум вещам:

Согласованность: если у меня есть 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(' ').

Ответ 3

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

Пример:

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

возвращает

['segment', 'segment']

Ответ 4

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

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

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

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

Ответ 5

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

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

Ответ 6

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

Простой пример: скажем, вы хотите проверить абсолютные и относительные имена файлов. Таким образом, вы можете сделать все это с помощью раскола, не требуя также проверки того, что является первым символом вашего имени файла.