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


155

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

І чи є більш зручний спосіб підрахунку рядків у рядку?


Відповіді:


247

Питання: Я використовую 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']

Зауважте, кількість полів результатів на один більший, ніж кількість роздільників. Подумайте перерізати мотузку. Якщо ви не робите порізів, у вас є одна деталь. Зробивши один зріз, дають дві частини. Зробивши два надрізи, дає три шматки. І так це з методом str.split (роздільник) Python :

>>> ''.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"

На запитання про те, щоб розбити ці рядки на поля, люди прагнуть описати обидва, використовуючи одне й те саме англійське слово "split". На запит прочитати такий код, як fields = line.split() абоfields = line.split(',') , люди прагнуть правильно інтерпретувати висловлювання як "розбиває рядок на поля".

Інструмент " Текст до стовпців" Microsoft Excel зробив аналогічний вибір API та включає обидва алгоритми розбиття в одному інструменті. Здається, люди подумки моделюють поділ поля як єдину концепцію, навіть якщо задіяно більше одного алгоритму.


28

Це , здається, просто так , як це повинно працювати, в відповідно до документацією :

Розщеплення порожнього рядка із заданим роздільником повертається [''] .

Якщо sep не вказано або немає, застосовується інший алгоритм розбиття: запуски послідовних пробілів розглядаються як єдиний роздільник, і результат не буде містити порожніх рядків на початку або в кінці, якщо рядок має провідну або кінцеву пробіли. Отже, розділення порожнього рядка або рядка, що складається з просто пробілів, з роздільником 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 завжди додає одне.
користувач829755

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.