Вернуть список слов из списка строк с регулярным выражением

Я запускаю следующий код в списке строк, чтобы вернуть список его слов:

words = [re.split('\\s+', line) for line in lines]

Однако в итоге я получаю что-то вроде:

[['import', 're', ''], ['', ''], ['def', 'word_count(filename):', ''], ...]

В отличие от желаемого:

['import', 're', '', '', '', 'def', 'word_count(filename):', '', ...]

Как я могу распаковать списки, которые re.split('\\s+', line) создает в приведенном выше понимании списка? Наивно, я пытался использовать *, но это не сработало.

(Я ищу простой и Pythonic-способ сделать это; у меня было искушение написать функцию, но я уверен, что язык подходит для этой проблемы.)


person Humphrey Bogart    schedule 06.04.2010    source источник
comment
В такие моменты я скучаю по concatMap от Haskell...   -  person perimosocordiae    schedule 06.04.2010


Ответы (4)


>>> import re
>>> from itertools import chain
>>> lines = ["hello world", "second line", "third line"]
>>> words = chain(*[re.split(r'\s+', line) for line in lines])

Это даст вам итератор, который можно использовать для перебора всех слов:

>>> for word in words:
...    print(word)
... 
hello
world
second
line
third
line

Создание списка вместо итератора — это просто обертывание итератора вызовом list:

>>> words = list(chain(*[re.split(r'\s+', line) for line in lines]))
person Pär Wieslander    schedule 06.04.2010
comment
Довольно удивительный способ сделать это, хотя я разочарован, что Python не позволяет сделать это менее загроможденным способом. Ваше здоровье. - person Humphrey Bogart; 08.04.2010
comment
В качестве альтернативы вы можете использовать chain.from_iterable без распаковки списка. - person Humphrey Bogart; 08.04.2010
comment
Легче отменить понимание - person machine yearning; 14.08.2011

Причина, по которой вы получаете список списков, заключается в том, что re.split() возвращает список, который затем «добавляется» к выводу понимания списка.

Непонятно, почему вы это используете (или, возможно, просто плохой пример), но если вы можете получить полное содержимое (все строки) в виде строки, которую вы можете просто сделать

words = re.split(r'\s+', lines)

если строки являются произведением:

open('filename').readlines()

использовать

open('filename').read()

вместо.

person unode    schedule 06.04.2010
comment
Используя Python 3 человек! Больше никаких readlines(), и все в Юникоде. - person Humphrey Bogart; 06.04.2010
comment
Кроме того, re.split не принимает аргумент списка (я уже пробовал). - person Humphrey Bogart; 06.04.2010
comment
@Кевин Тру; однако я использую list(file). - person Humphrey Bogart; 06.04.2010
comment
@Beau, глядя на твой пример, я не мог думать ни о чем другом, кроме чего-то, исходящего из файла или файлового типа. Следовательно, чтение его как строки (как указано выше) было бы возможным. - person unode; 06.04.2010

Вы всегда можете сделать это:

words = []
for line in lines:
  words.extend(re.split('\\s+',line))

Это не так элегантно, как однострочное понимание списка, но оно выполняет свою работу.

person perimosocordiae    schedule 06.04.2010

Просто наткнулся на этот старый вопрос, и я думаю, что у меня есть лучшее решение. Обычно, если вы хотите вложить понимание списка («добавить» каждый список), вы думаете в обратном направлении (не похоже на цикл). Это не то, что вы хотите:

>>> import re
>>> lines = ["hello world", "second line", "third line"]
>>> [[word for word in re.split(r'\s+', line)] for line in lines]
[['hello', 'world'], ['second', 'line'], ['third', 'line']]

Однако, если вы хотите «расширить» вместо «добавления» списки, которые вы создаете, просто исключите дополнительный набор квадратных скобок и переверните циклы for (вернув их в «правильный» порядок).

>>> [word for line in lines for word in re.split(r'\s+', line)]
['hello', 'world', 'second', 'line', 'third', 'line']

Это кажется мне более питоническим решением, поскольку оно основано на логике обработки списков, а не на какой-то случайной встроенной функции. Каждый программист должен знать, как это сделать (особенно те, кто пытается изучать Лисп!)

person machine yearning    schedule 08.08.2011