multiple into delimiters python string list split

python - into - ¿Cómo divido una cadena en una lista?



split list python (12)

Si tengo esta cadena:

2 + 24 * 48/32

¿Cuál es el enfoque más eficiente para crear esta lista?

[''2'', ''+'', ''24'', ''*'', ''48'', ''/'', ''32'']


s = "2 + 24 * 48/32"

p = re.compile (r ''(/ W +)'')

p.split (s)


Expresiones regulares:

>>> import re >>> splitter = re.compile(r''([+*/])'') >>> splitter.split("2+24*48/32")

Puede expandir la expresión regular para incluir cualquier otro carácter que quiera dividir.


Otra solución a esto sería evitar escribir una calculadora así por completo. Escribir un analizador RPN es mucho más simple y no tiene la ambigüedad inherente al escribir matemática con notación infija.

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 +'')


¿Por qué no usar SymPy ? Debería hacer lo que estás tratando de lograr.


Este es un problema de análisis sintáctico, por lo que ni regex no split () son la solución "buena". Use un generador de analizador en su lugar.

Yo miraría de cerca a pyparsing . También ha habido algunos artículos decentes sobre pyparsing en la Revista Python .


Da la casualidad de que los tokens que desea dividir ya son tokens de Python, por lo que puede usar el módulo tokenize incorporado. Es casi un trazador de líneas:

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'']


>>> import re >>> re.findall(r''/d+|/D+'', ''2+24*48/32=10'') [''2'', ''+'', ''24'', ''*'', ''48'', ''/'', ''32'', ''='', ''10'']

Coincide con dígitos consecutivos o sin dígitos consecutivos.

Cada partido se devuelve como un nuevo elemento en la lista.

Dependiendo del uso, puede necesitar modificar la expresión regular. Por ejemplo, si necesita unir números con un punto decimal.

>>> re.findall(r''[0-9/.]+|[^0-9/.]+'', ''2+24*48/32=10.1'') [''2'', ''+'', ''24'', ''*'', ''48'', ''/'', ''32'', ''='', ''10.1'']


Esto parece un problema de análisis sintáctico y, por lo tanto, me veo obligado a presentar una solución basada en técnicas de análisis sintáctico.

Si bien puede parecer que quieres ''dividir'' esta cadena, creo que lo que realmente quieres hacer es ''tokenizar''. Tokenización o lexxing es el paso de compilación antes del análisis. He modificado mi ejemplo original en una edición para implementar un analizador decente recursivo apropiado aquí. Esta es la forma más fácil de implementar un analizador a mano.

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()

La implementación del manejo de corchetes se deja como un ejercicio para el lector. Este ejemplo hará correctamente la multiplicación antes de la suma.


Esto no responde la pregunta exactamente, pero creo que resuelve lo que estás tratando de lograr. Lo agregaría como comentario, pero aún no tengo permiso para hacerlo.

Personalmente, aprovecharía la funcionalidad matemática de Python directamente con el ejecutivo:

expresión = "2 + 24 * 48/32"
exec "result =" + expresión
resultado de impresión
38


>>> import re >>> my_string = "2+24*48/32" >>> my_list = re.findall(r"-?/d+|/S", my_string) >>> print my_list [''2'', ''+'', ''24'', ''*'', ''48'', ''/'', ''32'']

Esto hará el truco. He encontrado este tipo de problema antes.


estoy seguro de que Tim quiso decir

splitter = re.compile(r''([/D])'').

si copias exactamente lo que tiene abajo, solo obtienes los digits no los operators .


Puede usar split desde el módulo re .

re.split (patrón, cadena, maxsplit = 0, flags = 0)

Separar cadena por las ocurrencias del patrón. Si se utilizan paréntesis de captura en el patrón, el texto de todos los grupos en el patrón también se devuelve como parte de la lista resultante.

Código de ejemplo:

import re data = re.split(r''(/D)'', ''2+24*48/32'')

/RE

Cuando no se especifica el indicador UNICODE, / D coincide con cualquier carácter que no sea un dígito; esto es equivalente al conjunto [^ 0-9].