Розділити пробіл комою та смужкою на Python


346

У мене є код python, який розбивається на коми, але не знімає пробіл:

>>> string = "blah, lots  ,  of ,  spaces, here "
>>> mylist = string.split(',')
>>> print mylist
['blah', ' lots  ', '  of ', '  spaces', ' here ']

Я вважаю за краще вилучити пробіл таким чином:

['blah', 'lots', 'of', 'spaces', 'here']

Я знаю, що я міг переглядати список і знімати (), кожен елемент, але, оскільки це Python, я здогадуюсь, що існує швидший, простіший і елегантніший спосіб зробити це.

Відповіді:


594

Використовуйте розуміння списку - простіше і так само легко читати, як forцикл.

my_string = "blah, lots  ,  of ,  spaces, here "
result = [x.strip() for x in my_string.split(',')]
# result is ["blah", "lots", "of", "spaces", "here"]

Див.: Документи Python щодо розуміння списку
Хороше 2-секундне пояснення розуміння списку.


1
Супер добре! Я додав один елемент наступним чином, щоб позбутися пустих записів у списку. > text = [x.strip () для x в text.split ('.'), якщо x! = '']
RandallShanePhD

@Sean: чи був недійсний / неповний код python вашим "початковим наміром публікації"? Згідно з даними огляду, це було: stackoverflow.com/review/sugges-edits/21504253 . Чи можете ви скажіть їм інше, внісши виправлення, якщо вони помиляються (знову)?
Корм

Оригінал було скопійовано з REPL (якщо я правильно пам’ятаю) і метою було розуміння основної концепції (використання розуміння списку для виконання операції) - але ви праві, це має більше сенсу, якщо ви бачите це розуміння списку створює новий список.
Шон Віейра

24

Розділіть, використовуючи регулярний вираз. Зауважте, я зробив випадок більш загальним із провідними пробілами. Ознайомлення зі списком полягає у видаленні нульових рядків спереду та ззаду.

>>> import re
>>> string = "  blah, lots  ,  of ,  spaces, here "
>>> pattern = re.compile("^\s+|\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['blah', 'lots', 'of', 'spaces', 'here']

Це працює, навіть якщо ^\s+не відповідає:

>>> string = "foo,   bar  "
>>> print([x for x in pattern.split(string) if x])
['foo', 'bar']
>>>

Ось чому вам потрібні ^ \ s +:

>>> pattern = re.compile("\s*,\s*|\s+$")
>>> print([x for x in pattern.split(string) if x])
['  blah', 'lots', 'of', 'spaces', 'here']

Бачите провідні простори в блазі?

Уточнення: вище використовується інтерпретатор Python 3, але результати однакові в Python 2.


8
Я вважаю, що [x.strip() for x in my_string.split(',')]це більше пітонічно для поставленого питання. Можливо, є випадки, коли потрібне моє рішення. Я оновлюю цей вміст, якщо перейду на нього.
tbc0

Навіщо це ^\s+потрібно? Я перевірив ваш код без нього, і він не працює, але я не знаю, чому.
laike9m

Якщо я використовую re.compile("^\s*,\s*$"), результат є [' blah, lots , of , spaces, here '].
laike9m

@ laike9m, я оновив свою відповідь, щоб показати тобі різницю. ^\s+робить. Як ви самі бачите, ^\s*,\s*$і бажаних результатів теж не повертається. Тож якщо ви хочете розділити за допомогою регулярного виразу, використовуйте ^\s+|\s*,\s*|\s+$.
tbc0

Перша відповідність порожня, якщо провідний шаблон (^ \ s +) не відповідає, тому ви отримуєте щось на зразок ['', 'foo', 'bar'] для рядка "foo, bar".
Стів Маккаулі

21

Я прийшов додати:

map(str.strip, string.split(','))

але бачив, що це вже згадував Джейсон Орендорф у коментарі .

Читаючи коментар Гленна Мейнард у тій самій відповіді, пропонуючи розуміння списку по карті, я почав цікавитись, чому. Я припускав, що він мається на увазі з міркувань продуктивності, але, звичайно, він міг би мати на увазі стилістичні причини чи щось інше (Гленн?).

Отже, швидкий (можливо, хибний?) Тест на моєму боксі з використанням трьох методів у циклі виявив:

[word.strip() for word in string.split(',')]
$ time ./list_comprehension.py 
real    0m22.876s

map(lambda s: s.strip(), string.split(','))
$ time ./map_with_lambda.py 
real    0m25.736s

map(str.strip, string.split(','))
$ time ./map_with_str.strip.py 
real    0m19.428s

що робить map(str.strip, string.split(','))переможець, хоча, здається , всі вони знаходяться в тому ж футбольному полі.

Безумовно, хоча карта (з лямбдаю чи без неї) не обов'язково повинна бути виключена з міркувань продуктивності, і для мене це принаймні настільки ж зрозуміло, як розуміння списку.

Редагувати:

Python 2.6.5 на Ubuntu 10.04


15

Просто вийміть пробіл із рядка перед тим, як розділити його.

mylist = my_string.replace(' ','').split(',')

10
Вигляд проблеми, якщо елементи, розділені комами, містять вбудовані пробіли, наприклад "you just, broke this".
Роберт Россні

1
Гейзе, -1 для цього. Ви, хлопці, жорсткі. Це вирішило його проблему, забезпечивши його вибіркові дані лише окремими словами, і не було конкретизації, що дані будуть фразами. Але ж, я думаю, ось як ви, хлопці, катаєтесь тут.
user489041

Добре дякую, користувачеві. Якщо бути справедливим, хоча я спеціально попросив розділити, а потім strip () і смуга видаляє провідні та відсталі пробіли і нічого не торкається між ними. Невелика зміна, і ваша відповідь спрацює чудово, хоча: mylist = mystring.strip (). Split (','), хоча я не знаю, чи це особливо ефективно.
Mr_Chimp

12

Я знаю, що на це вже відповіли, але якщо ви закінчите це робити багато, регулярні вирази можуть бути кращим способом:

>>> import re
>>> re.sub(r'\s', '', string).split(',')
['blah', 'lots', 'of', 'spaces', 'here']

\sВідповідає будь-якому прогалин, і ми просто замінити його з нового рядка ''. Більше інформації ви можете знайти тут: http://docs.python.org/library/re.html#re.sub


3
Ваш приклад не працюватиме на рядках, що містять пробіли. "бо, наприклад, це, один" став би "за", "прикладце це", "один". Не кажучи про те, що це BAD рішення (воно прекрасно працює на моєму прикладі), це просто залежить від завдання в руці!
Mr_Chimp

Так, це дуже правильно! Ви, ймовірно, можете відрегулювати регулярний вираз, щоб він міг обробляти рядки з пробілами, але якщо розуміння списку працює, я б сказав, що це дотримуйтесь;)
Brad Montgomery

2
import re
result=[x for x in re.split(',| ',your_string) if x!='']

це добре працює для мене.


2

re (як у звичайних виразах) дозволяє розділити на кілька символів одночасно:

$ string = "blah, lots  ,  of ,  spaces, here "
$ re.split(', ',string)
['blah', 'lots  ', ' of ', ' spaces', 'here ']

Це не добре працює для вашого прикладу рядка, але добре працює для списку, розділеного комою, пробілом. Для вашого прикладу рядка, ви можете комбінувати потужність re.split для розбиття на шаблони регулярних виразів, щоб отримати ефект "розділення на цей або інший".

$ re.split('[, ]',string)
['blah',
 '',
 'lots',
 '',
 '',
 '',
 '',
 'of',
 '',
 '',
 '',
 'spaces',
 '',
 'here',
 '']

На жаль, це некрасиво, але filterфішка зробить трюк:

$ filter(None, re.split('[, ]',string))
['blah', 'lots', 'of', 'spaces', 'here']

Вуаля!


2
Чому б не просто re.split(' *, *', string)?
Пол Томблін

4
@PaulTomblin хороша ідея. Можна також зробити це: re.split('[, ]*',string)для того ж ефекту.
Даннід

Деннід після написання зрозумів, що на початку та в кінці він не знімає пробілів, як це відповідає відповідь @ tbc0.
Пол Томблін

@PaulTomblinheh, і мій спростування [, ]*залишає порожній рядок в кінці списку. Я думаю, що фільтр - це все-таки приємна річ, щоб кинути його туди, або дотримуватися розуміння списку, як це відповідає головна відповідь.
Даннід

1

map(lambda s: s.strip(), mylist)було б трохи краще, ніж явно циклічно. Або для всієї справи відразу:map(lambda s:s.strip(), string.split(','))


10
Порада: будь-коли, коли ви виявите, що користуєтесь map, особливо якщо ви користуєтесь lambdaним, двічі перевірте, чи не слід використовувати розуміння списку.
Гленн Мейнард

11
Ви можете уникнути лямбда з map(str.strip, s.split(',')).
Джейсон Орендорф


1
import re
mylist = [x for x in re.compile('\s*[,|\s+]\s*').split(string)]

Просто кома або хоча б один пробіл з / без попередніх / наступних пробілів.

Будь ласка, спробуй!


0

map(lambda s: s.strip(), mylist)було б трохи краще, ніж явно циклічно.
Або для всієї справи відразу:

map(lambda s:s.strip(), string.split(','))

Це в основному все, що потрібно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.