Как правильно разбить этот список строк?
У меня есть список строк, таких как:
['z+2-44', '4+55+z+88']
Как я могу разбить эти строки в списке так, чтобы это было что-то вроде
[['z','+','2','-','44'],['4','+','55','+','z','+','88']]
Я уже пытался использовать метод split
, который уже разделяет 44 на 4 и 4, и я не уверен, что еще попробовать.
Ответы
Ответ 1
Вы можете использовать регулярное выражение:
import re
lst = ['z+2-44', '4+55+z+88']
[re.findall('\w+|\W+', s) for s in lst]
# [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
\w+|\W+
соответствует шаблону, состоящему либо из символов слова (буквенно-цифровые значения в вашем случае), либо несловных символов (+-
знаков в вашем случае).
Ответ 2
Это будет работать, используя itertools.groupby
z = ['z+2-44', '4+55+z+88']
print([["".join(x) for k,x in itertools.groupby(i,str.isalnum)] for i in z])
выход:
[['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
Он просто группирует символы, если они являются буквенно-цифровыми (или нет), просто присоединяйте их обратно в понимании списка.
EDIT: общий случай калькулятора с круглыми скобками задан в качестве последующего вопроса здесь. Если z
выглядит следующим образом:
z = ['z+2-44', '4+55+((z+88))']
то с предыдущей группировкой получим:
[['z', '+', '2', '-', '44'], ['4', '+', '55', '+((', 'z', '+', '88', '))']]
Это непросто разобрать в терминах токенов. Таким образом, изменение будет join
только в том случае, если alphanum и пусть в качестве списка, если нет, сглаживание в конце с помощью chain.from_iterable
:
print([list(itertools.chain.from_iterable(["".join(x)] if k else x for k,x in itertools.groupby(i,str.isalnum))) for i in z])
который дает:
[['z', '+', '2', '-', '44'], ['4', '+', '55', '+', '(', '(', 'z', '+', '88', ')', ')']]
(обратите внимание, что альтернативный ответ регулярного выражения также можно адаптировать следующим образом: [re.findall('\w+|\W', s) for s in lst]
(обратите внимание на отсутствие +
после W
)
также "".join(list(x))
немного быстрее, чем "".join(x)
, но я позволю вам добавить его, чтобы избежать изменения видимости этого уже сложного выражения.
Ответ 3
Альтернативное решение с использованием re.split:
l = ['z+2-44', '4+55+z+88']
print([list(filter(None, re.split(r'(\w+)', i))) for i in l])
Выход:
[['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
Ответ 4
Вы можете использовать только встроенные функции str.replace()
и str.split()
в понимании списка:
In [34]: lst = ['z+2-44', '4+55+z+88']
In [35]: [s.replace('+', ' + ').replace('-', ' - ').split() for s in lst]
Out[35]: [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
Но обратите внимание, что это не эффективный подход для более длинных строк. В этом случае лучше всего использовать регулярное выражение.
В качестве еще одного питонического способа вы также можете использовать модуль tokenize
:
In [56]: from io import StringIO
In [57]: import tokenize
In [59]: [[t.string for t in tokenize.generate_tokens(StringIO(i).readline)][:-1] for i in lst]
Out[59]: [['z', '+', '2', '-', '44'], ['4', '+', '55', '+', 'z', '+', '88']]
Модуль tokenize предоставляет лексический сканер для исходного кода Python, реализованный в Python. Сканер в этом модуле также возвращает комментарии в качестве токенов, что делает его полезным для реализации "симпатичных принтеров", в том числе колоризаторов для экранных дисплеев.
Ответ 5
Если вы хотите придерживаться split
(следовательно, избегая регулярного выражения), вы можете предоставить ему необязательный символ для разделения:
>>> testing = 'z+2-44'
>>> testing.split('+')
['z', '2-44']
>>> testing.split('-')
['z+2', '44']
Итак, вы можете взломать что-то, связав команды разделения.
Однако использование регулярных выражений, вероятно, было бы более читаемым:
import re
>>> re.split('\+|\-', testing)
['z', '2', '44']
Это просто означает "разделить строку на любой символ + или" (обратные косые черты являются escape-символами, потому что оба они имеют особое значение в регулярном выражении.
Наконец, в этом конкретном случае, я полагаю, что цель - это что-то вроде "раскола при каждом неабелевом числовом символе", и в этом случае регулярное выражение еще может сохранить день:
>>> re.split('[^a-zA-Z0-9]', testing)
['z', '2', '44']
Конечно, стоит отметить, что существует еще миллион других решений, как обсуждалось в некоторых других обсуждениях SO.
Python: Разделить строку с несколькими разделителями
Разделить строки с несколькими разделителями?
Мои ответы здесь нацелены на простой, читаемый код, а не на производительность, в честь Дональда Кнута