-2

I am trying to create JSON from a string with an expression, but before that I have to replace the operand.

This is user input:

"Apple == 5 & (Plum == 7 | Pear == 8)"

I have to replace "==" to "eq", "&" to "and", etc. (and more logical expressions if it is necessary)

"Apple eq 5 and (Plum eq 7 or Pear eq 8)"

And finally, it should be a result in JSON, like this:

{
                "CategoryId": 0,

                "FilterRequest":
                {

                               "Page": 1,

                               "PageSize": 10,

                               "Filter": 
                               { 
                                   "Logic": "and",

                                   "Filters": [
                                       { 
                                           "Logic": "or",
                                           "Filters": [
                                               { 
                                                   "Field": "Plum",
                                                   "Operator": "eq", 
                                                   "Value": "7"
                                               },
                                               { 
                                                   "Field": "Pear",
                                                   "Operator": "eq", 
                                                   "Value": "8"
                                               }
                                           ]
                                       },
                                       { 
                                           "Field": "Apple",
                                           "Operator": "eq", 
                                           "Value": "5"
                                       }
                                   ]
                               }

                }
}

Could you tell me your ideas how to do it? Thank you

EDITED : 14/5/2019

I tried to find as much information as possible about my problem and I think I'm halfway. If I ever chose the right way. Could you give me feedback or advice about the code below?

string = "Apple == 5 & (Plum == 7 | Pear == 8)"

string = string.replace('==', ' eq ')
string = string.replace('<>', ' ne ')
string = string.replace('>' , ' gt ')
string = string.replace('>=', ' ge ')
string = string.replace('<' , ' lt ')
string = string.replace('<=', ' le ')
string = string.replace('&' , ' and ')
string = string.replace('|' , ' or ')
string = string.replace('!=', ' not ')

print(string)
# "Apple eq 5 and (Plum eq 7 or Pear eq 8)"


import pyparsing as pp

    operator = pp.Regex(r">=|<=|!=|>|<|=|eq").setName("operator")
    number = pp.Regex(r"[+-]?\d+(:?\.\d*)?(:?[eE][+-]?\d+)?")
    identifier = pp.Word(pp.alphas, pp.alphanums + "_")
    and_ = CaselessLiteral("and").setResultsName("Logic")
    or_ = CaselessLiteral("or").setResultsName("Logic")
    not_ = CaselessLiteral("not").setResultsName("Logic")
    logic = [
            (and_, 2, (pp.opAssoc.LEFT),),
            (or_, 2, pp.opAssoc.LEFT,),
            (not_, 1, pp.opAssoc.RIGHT,),
            ]
    comparison_term = (identifier | number)
    condition = pp.Group(comparison_term("Field") + operator("Operator") + comparison_term("Value"))
    expr = pp.operatorPrecedence(condition("Filters"), logic).setResultsName("Filter")

pars = expr.parseString(string).dump()

import json

    with open("C:\\Users\\palo173\\Desktop\\example.json","w") as f:
        json.dump(o,f)

Actual result, but unfortunately not final. I'd like to hear your ideas as to what to do next.

{
    "Filter": {
        "Filter": {
            "Filters": [
                {
                    "Field": "Apple",
                    "Operator": "eq",
                    "Value": "5"
                },
                {
                    "Filters": [
                        {
                            "Field": "Plum",
                            "Operator": "eq",
                            "Value": "7"
                        },
                        {
                            "Field": "Pear",
                            "Operator": "eq",
                            "Value": "8"
                        }
                    ],
                    "Logic": "or"
                }
            ],
            "Logic": "and"
        }
    }
}
Stidgeon
  • 2,673
  • 8
  • 20
  • 28
palo173
  • 13
  • 9
  • 2
    What have you tried so far? – IonicSolutions May 02 '19 at 14:57
  • 1
    The [shunting-yard algorithm](https://en.wikipedia.org/wiki/Shunting-yard_algorithm) is generally effective at parsing expressions that contain parenthetical sub-expressions and binary operators of varying precedence. – Kevin May 02 '19 at 14:59
  • Thank you @Kevin it looks like something, what I need but unfortunately I did not find good example in python for me, what I could transform into my form, to solve my problem. – palo173 May 06 '19 at 11:48
  • Pyparsing's returned ParseResults has an `asDict` method so that you can directly go from the returned value to a dict, without going through the deprecated `asXML` to XML and then xmltodict to convert to a dict. And if you use `with open(...) as f:`, there is no need for an `f.close()`, the `with` statement will automatically call the file's `__exit__` method, which calls `f.close()`. That's why we use this statement for files. – PaulMcG May 11 '19 at 00:51
  • @PaulMcG Thank you. You are right. I edited it according to your recommendation ... I read, that you are father of pyparsing, so maybe you should help me what next ? ... I try to edit the code, when I come up with something new. – palo173 May 14 '19 at 13:22

1 Answers1

0

I would suggest to use the

string.replace(old, new, count)
# count is optional, leave it blank like below and it does all occurences

for example

string = "Apple == 5 & (Plum == 7 | Pear == 8)"

string.replace('==', 'eq')
string.replace('&', 'and')
string.replace('|', 'or')

print(string)

>Apple eq 5 and (Plum eq 7 or Pear eq 8
# and so on

now this does only the replacing, maybe use a for loop to iterate to a list of strings, but I figure you can do it.

bv_Martn
  • 139
  • 12