2017-02-19 14 views
14

У меня есть список строк, таких, как это:Как правильно разбить этот список строк?

['z+2-44', '4+55+z+88'] 

Как я могу разделить эти строки в списке такого, что было бы что-то вроде

[['z','+','2','-','44'],['4','+','55','+','z','+','88']] 

Я попытался с помощью split метод уже однако, что разделяет 44 на 4 и 4, и я не уверен, что еще попробовать.

+1

Спецификация неполная, я думаю. Что относительно математических операторов * и /? Как насчет переменных a, b и c? Является ли pi константой, переменной или p * i? Заданный вопрос привлечет ответы, которые могут быть не очень полезны для всех ваших случаев. –

+0

@martineau Я считаю, что вопрос [this] (http://stackoverflow.com/questions/4736/learning-regular-expressions) не является правильным дубликатом. – Kasramvd

+0

@ Kasramvd: Мне было бы интересно услышать, почему вы так думаете. – martineau

ответ

26

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

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+ соответствует шаблону, который состоит либо из символов слова (буквенно-цифровых значений в вашем случае) или символы не слово (+- знаков в вашем случае).

14

Это будет работать, используя 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: в общем случае калькулятор с круглыми скобками был задан в качестве последующего вопроса here. Если 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), но Я позволю вам добавить его, чтобы избежать изменения видимости этого уже сложного выражения.

+1

Вы избили меня на 3 секунды: P –

+1

вы не больной неудачник, как я вижу :) Спасибо за редактирование –

6

Альтернативное решение с использованием 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']] 
-1

Если вы хотите придерживаться split (следовательно, избежать регулярных выражений), вы можете предоставить ему необязательный символ для разделения на:

>>> testing = 'z+2-44' 
>>> testing.split('+') 
['z', '2-44'] 
>>> testing.split('-') 
['z+2', '44'] 

Итак, вы можете взломать что-то на c haining команды разделения.

Однако, используя регулярные выражения, вероятно, будет более удобным для чтения:

import re 

>>> re.split('\+|\-', testing) 
['z', '2', '44'] 

Это просто говорит «разбить строку на любом + или - символ» (обратные слеши экранирующих символов, потому что оба эти имеют специальные смысл в регулярных выражениях

Наконец, в данном конкретном случае, я полагаю, цель что-то вдоль линий «раскола на каждом, не буквенно-цифровой символ», в этом случае регулярное выражение может еще спасти день:.

>>> re.split('[^a-zA-Z0-9]', testing) 
['z', '2', '44'] 

Конечно, стоит отметить, что существует еще миллион других решений, как обсуждалось в некоторых других обсуждениях SO.

Python: Split string with multiple delimiters

Split Strings with Multiple Delimiters?

Мои ответы здесь ориентированы на простой, читаемый код, а не производительность, в честь Дональда Кнута

+1

Аскер хочет, чтобы эти знаки были в приведенном списке. не только z 2 44. – Lafexlos

+0

Ах, да, лучше бы лучше прочитать вопрос. Я бы обновил ответ, но я вижу, что на этот вопрос уже был дан ответ. Продолжать! – MrName

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. Сканер в этом модуле также возвращает комментарии в качестве токенов, что делает его полезным для реализации «симпатичных принтеров», включая раскраски для экранных дисплеев.