Operadores de mapas extraídos de la subcadena

Tengo una list of dict :

 print (L) [{0: 'x==1', 1: 'y==2', 2: 'z!=1'}, {0: 'x==1', 1: 'y1'}] 

Quiero crear tuplas con valor antes que operadores, operadores y valor después:

 #first step wanted = [[('x', '==', '1'), ('y', '==', '2'), ('z', '!=', '1')], [('x', '==', '1'), ('y', '', '1')]] 

Y luego mapear segundo valor por los operadores:

 import operator ops = {'>': operator.gt, '=': operator.ge, '<=': operator.le, '==': operator.eq, '!=': operator.ne} #expected final output wanted = [[('x', , '1'), ('y', , '2'), ('z', , '1')], [('x', , '1'), ('y', , '3'), ('z', , '1')]] 

Lo bash:

 L = [[re.findall(r'(.*)([=!]+)(.*)', v)[0] for k, v in x.items()] for x in L] print (L) [[('x=', '=', '1'), ('y=', '=', '2'), ('z!', '=', '1')], [('x=', '=', '1'), ('y', '1')]] L = [[ops[y[1]] for y in x] for x in L] 

Pero el problema es un error en las subcadenas intermedias coincidentes: operadores y, a continuación, un valor equivocado de operador.

¿Qué es correx regex para una coincidencia correcta? O aquí hay alguna otra solución posible. por ejemplo, por string.partition ? Estoy abierto a todas las soluciones posibles.

Creo que el enfoque más directo, si sus entradas son de hecho tan simples, es dividir en los caracteres del operador:

 In [1]: import re In [2]: data = [{0: 'x==1', 1: 'y==2', 2: 'z!=1'}, {0: 'x==1', 1: 'y<=3', 2: 'z>1'}] In [3]: rgx = re.compile(r'([<>=!]+)') In [4]: [[rgx.split(v) for v in d.values()] for d in data] Out[4]: [[['x', '==', '1'], ['y', '==', '2'], ['z', '!=', '1']], [['x', '==', '1'], ['y', '<=', '3'], ['z', '>', '1']]] 

Tenga en cuenta que si agrega un grupo de captura a la expresión regular del divisor, se incluirá.

Y luego, para terminar:

 In [11]: ops = {'>': operator.gt, ...: '<': operator.lt, ...: '>=': operator.ge, ...: '<=': operator.le, ...: '==': operator.eq, ...: '!=': operator.ne} ...: In [12]: parsed = [[rgx.split(v) for v in d.values()] for d in data] In [13]: [[(x, ops[op], y) for x,op,y in ps] for ps in parsed] Out[13]: [[('x', , '1'), ('y', , '2'), ('z', , '1')], [('x', , '1'), ('y', , '3'), ('z', , '1')]] 

Cambie el primer codex de expresiones ambiciosas al único carácter de palabra:

 L = [{0: 'x==1', 1: 'y==2', 2: 'z!=1'}, {0: 'x==1', 1: 'y<=3', 2: 'z>1'}] L = [[re.findall(r'(\w)([<>=!]+)(.*)', v)[0] for k, v in x.items()] for x in L] [[(y[0],ops[y[1]],y[2]) for y in x] for x in L] [[('x', , '1'), ('y', , '2'), ('z', , '1')], [('x', , '1'), ('y', , '3'), ('z', , '1')]] 

O según la sugerencia de jezrael de los comentarios (1 línea de comprehesion de lista):

 L = [[[(z[0], ops[z[1]], z[2]) for z in re.findall(r'(\w)([<>=!]+)(.*)', v)][0] for k, v in x.items()] for x in L] 

O no necesitamos claves, por lo que usar valores directamente:

 L = [[[(z[0], ops[z[1]], z[2]) for z in re.findall(r'(\w)([<>=!]+)(.*)', v)][0] for v in x.values()] for x in L] 

El problema es que * es un codificador de caracteres codicioso. Entonces, en x==1 , si * puede coincidir con más de un carácter, lo hará, mientras sigue satisfaciendo al segundo grupo ([<>=!]+) Con un solo carácter = .

Soluciones:

  1. Asumiendo que los grupos que no son operadores nunca incluirán < , > , = o ! , en lugar de usar * , usa el conjunto de caracteres negativos:

    re.findall(r'([^<>=!]+)([<>=!]+)([^<>=!]+)', v)

  2. Use la alternancia con la barra vertical para capturar al operador:

    re.findall(r'(.*)((?:>|<|<=|>=|==|!=))(.*)', v)