Разделить запятыми и убрать пробелы в Python


347

У меня есть некоторый код Python, который разделяется на запятую, но не удаляет пробелы:

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

Я предпочел бы в конечном итоге удалить пробелы, как это:

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

Я знаю, что мог бы пройтись по списку и обрезать () каждый элемент, но, поскольку это Python, я предполагаю, что есть более быстрый, простой и элегантный способ сделать это.

Ответы:


596

Использовать понимание списка - проще и так же легко читаемо, как 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 твоим «исходным намерением»? Согласно обзору wankers это было: stackoverflow.com/review/suggested-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

Ну все равно спасибо, пользователь. Чтобы быть справедливым, я специально попросил split, а затем strip () и 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
Ваш пример не будет работать со строками, содержащими пробелы. «для этого, например, один» станет «для», «пример этот», «один». Не говоря о том, что это ПЛОХОЕ решение (оно отлично работает на моем примере), оно зависит только от поставленной задачи!
Mr_Chimp

Да, это очень правильно! Вы могли бы, вероятно, настроить регулярное выражение так, чтобы оно могло обрабатывать строки с пробелами, но если понимание списка работает, я бы сказал, придерживайтесь его;)
Брэд Монтгомери,

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 для разделения на шаблоны регулярных выражений, чтобы получить эффект «split-on-this-or-that».

$ 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.