Операторы карты, извлеченные из подстроки - PullRequest
0 голосов
/ 03 октября 2018

У меня есть list of dict s:

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

Я хочу создать кортежи со значением до операторов, операторов и значение после:

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

И затем отобразить второе значение с помощью операторов:

import operator

ops = {'>': operator.gt,
        '<': operator.lt,
       '>=': operator.ge,
       '<=': operator.le,
       '==': operator.eq,
        '!=': operator.ne}

#expected final output
wanted = [[('x', <built-in function eq>, '1'), 
           ('y', <built-in function eq>, '2'), 
           ('z', <built-in function ne>, '1')], 
          [('x', <built-in function eq>, '1'), 
           ('y', <built-in function le>, '3'), 
           ('z', <built-in function gt>, '1')]]

Я пытаюсь:

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<', '=', '3'), ('z', '>', '1')]]

L = [[ops[y[1]] for y in x] for x in L]

Но проблема в том, что неверно сопоставлены средние подстроки - операторы, а затем неверно сопоставлено значение оператора.

Что такое правильное регулярное выражение для правильногоматч?Или вот другое возможное решение.например на string.partition?Мне открыты все возможные решения.

Ответы [ 3 ]

0 голосов
/ 03 октября 2018

Замените регулярное выражение 1-й подстроки жадного метода на единственный символ слова:

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', <function _operator.eq>, '1'),
  ('y', <function _operator.eq>, '2'),
  ('z', <function _operator.ne>, '1')],
 [('x', <function _operator.eq>, '1'),
  ('y', <function _operator.le>, '3'),
  ('z', <function _operator.gt>, '1')]]

Или согласно jezrael предложение из комментариев (понимание списка из 1 строки):

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]

Или нам не нужны ключи, поэтому мы должны использовать значения напрямую:

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]
0 голосов
/ 03 октября 2018

Проблема в том, что * является жадным сопоставителем символов.Таким образом, в x==1, если * может соответствовать более чем одному символу, оно будет соответствовать второй группе ([<>=!]+) с одним = символом.

Решения:

  1. Предполагая, что группы без операторов никогда не будут включать <, >, = или !, вместо использования * используйте набор отрицательных символов:

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

  2. Используйте чередование с вертикальной чертой для захвата оператора:

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

0 голосов
/ 03 октября 2018

Я думаю, что самый простой подход, если ваши входные данные действительно такие простые, заключается в разбиении на символы оператора:

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

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

И затем, чтобы закончить его:

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', <function _operator.eq>, '1'),
  ('y', <function _operator.eq>, '2'),
  ('z', <function _operator.ne>, '1')],
 [('x', <function _operator.eq>, '1'),
  ('y', <function _operator.le>, '3'),
  ('z', <function _operator.gt>, '1')]]
...