如何将一个string分割成一个列表?
如果我有这个string:
2 + 24 *32分之48
什么是创build这个列表最有效的方法:
['2','+','24','*','48','/','32']
恰好碰巧你要分割的令牌已经是Python令牌了,所以你可以使用内置的tokenize
模块。 这几乎是一线:
from cStringIO import StringIO from tokenize import generate_tokens STRING = 1 list(token[STRING] for token in generate_tokens(StringIO('2+24*48/32').readline) if token[STRING]) ['2', '+', '24', '*', '48', '/', '32']
你可以使用从re
模块split
。
re.split(pattern,string,maxsplit = 0,flags = 0)
由模式发生的分割string。 如果在模式中使用捕获括号,则模式中所有组的文本也会作为结果列表的一部分返回。
示例代码:
import re data = re.split(r'(\D)', '2+24*48/32')
\ d
当未指定UNICODE标志时,\ D匹配任何非数字字符; 这相当于set [^ 0-9]。
这看起来像一个parsing问题,因此我不得不提出一个基于parsing技术的解决scheme。
虽然看起来你想“分割”这个string,但我认为你真正想要做的是“标记”它。 Tokenization或Lexxing是parsing之前的编译步骤。 我已经修改了我原来的例子,在这里实现了一个适当的recursion裁剪。 这是手工实现parsing器的最简单方法。
import re patterns = [ ('number', re.compile('\d+')), ('*', re.compile(r'\*')), ('/', re.compile(r'\/')), ('+', re.compile(r'\+')), ('-', re.compile(r'\-')), ] whitespace = re.compile('\W+') def tokenize(string): while string: # strip off whitespace m = whitespace.match(string) if m: string = string[m.end():] for tokentype, pattern in patterns: m = pattern.match(string) if m: yield tokentype, m.group(0) string = string[m.end():] def parseNumber(tokens): tokentype, literal = tokens.pop(0) assert tokentype == 'number' return int(literal) def parseMultiplication(tokens): product = parseNumber(tokens) while tokens and tokens[0][0] in ('*', '/'): tokentype, literal = tokens.pop(0) if tokentype == '*': product *= parseNumber(tokens) elif tokentype == '/': product /= parseNumber(tokens) else: raise ValueError("Parse Error, unexpected %s %s" % (tokentype, literal)) return product def parseAddition(tokens): total = parseMultiplication(tokens) while tokens and tokens[0][0] in ('+', '-'): tokentype, literal = tokens.pop(0) if tokentype == '+': total += parseMultiplication(tokens) elif tokentype == '-': total -= parseMultiplication(tokens) else: raise ValueError("Parse Error, unexpected %s %s" % (tokentype, literal)) return total def parse(tokens): tokenlist = list(tokens) returnvalue = parseAddition(tokenlist) if tokenlist: print 'Unconsumed data', tokenlist return returnvalue def main(): string = '2+24*48/32' for tokentype, literal in tokenize(string): print tokentype, literal print parse(tokenize(string)) if __name__ == '__main__': main()
括号的处理的实施留给读者作为练习。 这个例子将在添加之前正确地进行乘法运算。
>>> import re >>> re.findall(r'\d+|\D+', '2+24*48/32=10') ['2', '+', '24', '*', '48', '/', '32', '=', '10']
匹配连续的数字或连续的非数字。
每个匹配作为列表中的新元素返回。
根据使用情况,您可能需要更改正则expression式。 例如,如果您需要与小数点匹配的数字。
>>> re.findall(r'[0-9\.]+|[^0-9\.]+', '2+24*48/32=10.1') ['2', '+', '24', '*', '48', '/', '32', '=', '10.1']
这是一个parsing问题,所以正则expression式不是split()是“好”的解决scheme。 使用parsing器生成器来代替。
我会密切关注pyparsing 。 在Python杂志中也有一些关于pyparsing的体面的文章。
常用expression:
>>> import re >>> splitter = re.compile(r'([+*/])') >>> splitter.split("2+24*48/32")
您可以展开正则expression式以包含要分割的其他任何字符。
s =“2 + 24 * 48/32”
p = re.compile(r'(\ W +)')
p.split(S)
解决这个问题的另一个办法是避免写一个像这样的计算器。 编写一个RPNparsing器要简单得多,而且没有用中缀表示法编写math的固有含糊之处。
import operator, math calc_operands = { '+': (2, operator.add), '-': (2, operator.sub), '*': (2, operator.mul), '/': (2, operator.truediv), '//': (2, operator.div), '%': (2, operator.mod), '^': (2, operator.pow), '**': (2, math.pow), 'abs': (1, operator.abs), 'ceil': (1, math.ceil), 'floor': (1, math.floor), 'round': (2, round), 'trunc': (1, int), 'log': (2, math.log), 'ln': (1, math.log), 'pi': (0, lambda: math.pi), 'e': (0, lambda: math.e), } def calculate(inp): stack = [] for tok in inp.split(): if tok in self.calc_operands: n_pops, func = self.calc_operands[tok] args = [stack.pop() for x in xrange(n_pops)] args.reverse() stack.append(func(*args)) elif '.' in tok: stack.append(float(tok)) else: stack.append(int(tok)) if not stack: raise ValueError('no items on the stack.') return stack.pop() if stack: raise ValueError('%d item(s) left on the stack.' % len(stack)) calculate('24 38 * 32 / 2 +')
>>> import re >>> my_string = "2+24*48/32" >>> my_list = re.findall(r"-?\d+|\S", my_string) >>> print my_list ['2', '+', '24', '*', '48', '/', '32']
这将做的伎俩。 以前我遇到过这样的问题。
为什么不使用SymPy ? 它应该做你想要实现的。
这并不是完全回答这个问题,但我相信它解决了你想要达到的目标。 我会将其添加为评论,但我还没有权限这样做。
我个人会直接利用exec的Python的mathfunction:
expression式=“2 + 24 * 48/32”
exec “result =”+expression式
打印结果
38
我确定蒂姆的意思
splitter = re.compile(r'([\D])').
如果你确切地复制了他的下落,你只能得到digits
而不是operators
。