将简单表达式转换为jsonlogic格式

发布于 2025-01-24 03:05:48 字数 1317 浏览 0 评论 0原文

使用Python,我需要将表达式转换为 jsonlogic 格式。诸如布尔表达的表达,如果其他 /三元表达式等。

如何实现这一目标?

ps我看到我们有一个js-to-json-logic 在JavaScript中相同。找不到其等效的Python库。

示例1:

输入:

((var001 == "Y"))?1:((var001 == "N"))?0:false

输出:

{
"if": [
  {
    "==": [
      {
        "var": "var001"
      },
      "Y"
    ]
  },
  1,
  {
    "if": [
      {
        "==": [
          {
            "var": "var001"
          },
          "N"
        ]
      },
      0,
      false
    ]
  }
]
}

示例2:

输入:

CustomFunc(var123, "%Y-%d", (var123 == "N" ? 0 : 123))

注意:输入可以是自定义函数(具有n个参数)的组合,并且这些参数中的任何一个都可以是单个属性或进一步表达式的组合。

输出:

{
  "CustomFunc": [
    {
      "var": "var123"
    },
    "%Y-%d",
    {
    "if": [
        {
        "==": [
                {
                    "var": "var123"
                },
                "N"
            ]
        },
        0,
        123
    ]
    }
  ]
}

示例3:

输入:

9 + 2 - 6 * 4

按Opertor优先级和括号的输出

Using python, I need to convert expressions into JsonLogic format. Expressions such as Boolean expressions, if else / ternary expressions, etc.

Any suggestions how to achieve this ?

P.S. I see that we have a js-to-json-logic library for the same in Javascript. Could not find its equivalent Python Library.

Example 1:

Input:

((var001 == "Y"))?1:((var001 == "N"))?0:false

Output:

{
"if": [
  {
    "==": [
      {
        "var": "var001"
      },
      "Y"
    ]
  },
  1,
  {
    "if": [
      {
        "==": [
          {
            "var": "var001"
          },
          "N"
        ]
      },
      0,
      false
    ]
  }
]
}

Example 2:

Input:

CustomFunc(var123, "%Y-%d", (var123 == "N" ? 0 : 123))

Note: Input could be a combination of custom function (having n parameters) and any of these parameters could be single attribute or a combination of further expressions.

Output:

{
  "CustomFunc": [
    {
      "var": "var123"
    },
    "%Y-%d",
    {
    "if": [
        {
        "==": [
                {
                    "var": "var123"
                },
                "N"
            ]
        },
        0,
        123
    ]
    }
  ]
}

Example 3:

Input:

9 + 2 - 6 * 4

Output as per opertor precedence and parenthesis

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

懒的傷心 2025-01-31 03:05:48

Pyparsing的InfixNotation方法将允许定义一元,二进制和三元运算符(例如您的expr?true_value:false_value operations)。该代码将解析您的表达式:

import pyparsing as pp
ppc = pp.common

bool_constant = pp.oneOf("true false")
integer = ppc.integer()
ident = ppc.identifier()
qs = pp.quotedString()

operand = qs | integer | bool_constant | ident

comparison_operator = pp.oneOf("< > >= <=")
eq_operator = pp.oneOf("== !=")

expr = pp.infixNotation(operand,
                        [
                            (comparison_operator, 2, pp.opAssoc.LEFT),
                            (eq_operator, 2, pp.opAssoc.LEFT),
                            (('?', ':'), 3, pp.opAssoc.LEFT),
                        ])

expr.runTests("""\
                ((var001 == "Y"))?1:((var001 == "N"))?0:false
                """
              )

让解析器是战斗的前半部分。 这个答案情况是评估结果,但是对于您来说,您可能想执行这些类别的AS_JSONLOGIC()方法,以散发JSONLOGIC格式的等效表格。

编辑:

好的,只向您展示解析器可能没有什么帮助。因此,这是带有添加类的解析器及其各自的AS_JSONLOGIC()方法。

import pyparsing as pp
ppc = pp.common

bool_constant = pp.oneOf("true false")
integer = ppc.integer()
ident = ppc.identifier()
qs = pp.quotedString()

class Node:
    def __init__(self, tokens):
        self._tokens = tokens
        self.assign_vars()

    def assign_vars(self):
        pass

    def as_jsonlogic(self) -> str:
        raise NotImplementedError()

class Verbatim(Node):
    def as_jsonlogic(self) -> str:
        return str(self._tokens[0])

class Identifier(Node):
    def as_jsonlogic(self) -> str:
        return f'{{ "var": "{self._tokens[0]}" }}'

class Comparison(Node):
    def assign_vars(self):
        self.oper1, self.operator, self.oper2 = self._tokens[0]

    def as_jsonlogic(self) -> str:
        return f'{{ "{self.operator}" : [ {self.oper1.as_jsonlogic()}, {self.oper2.as_jsonlogic()} ]  }}'

class Ternary(Node):
    def assign_vars(self):
        self.condition, _, self.true_value, _, self.false_value = self._tokens[0]

    def as_jsonlogic(self) -> str:
        return f'{{ "if" : [ {self.condition.as_jsonlogic()}, {self.true_value.as_jsonlogic()}, {self.false_value.as_jsonlogic()} ]  }}'

# add the classes a parse actions, so that each expression gets converted to a Node subclass instance
qs.add_parse_action(Verbatim)
integer.add_parse_action(Verbatim)
bool_constant.add_parse_action(Verbatim)
ident.add_parse_action(Identifier)

operand = qs | integer | bool_constant | ident

comparison_operator = pp.oneOf("< > >= <=")
eq_operator = pp.oneOf("== !=")

# add parse actions to each level of the infixNotation    
expr = pp.infixNotation(operand,
                        [
                            (comparison_operator, 2, pp.opAssoc.LEFT, Comparison),
                            (eq_operator, 2, pp.opAssoc.LEFT, Comparison),
                            (('?', ':'), 3, pp.opAssoc.RIGHT, Ternary),
                        ])

# use runTests to run some tests, with a post_parse function
# to call as_jsonlogic() on the parsed result
expr.runTests("""\
    "Y"
    false
    100
    var001
    (var001 == 100)
    ((var001 == "Y"))?1:((var001 == "N"))?0:false
    """, post_parse=lambda s, r: r[0].as_jsonlogic())

印刷品:

"Y"
"Y"

false
false

100
100

var001
{ "var": "var001" }

(var001 == 100)
{ "==" : [ { "var": "var001" }, 100 ]  }

((var001 == "Y"))?1:((var001 == "N"))?0:false
{ "if" : [ { "==" : [ { "var": "var001" }, "Y" ]  }, 1, { "if" : [ { "==" : [ { "var": "var001" }, "N" ]  }, 0, false ]  } ]  }

我将漂亮的凹痕留给您。

Pyparsing's infixNotation method will permit the definition of unary, binary, and ternary operators (such as your expr ? true_value : false_value operations). This code will parse your given expression:

import pyparsing as pp
ppc = pp.common

bool_constant = pp.oneOf("true false")
integer = ppc.integer()
ident = ppc.identifier()
qs = pp.quotedString()

operand = qs | integer | bool_constant | ident

comparison_operator = pp.oneOf("< > >= <=")
eq_operator = pp.oneOf("== !=")

expr = pp.infixNotation(operand,
                        [
                            (comparison_operator, 2, pp.opAssoc.LEFT),
                            (eq_operator, 2, pp.opAssoc.LEFT),
                            (('?', ':'), 3, pp.opAssoc.LEFT),
                        ])

expr.runTests("""\
                ((var001 == "Y"))?1:((var001 == "N"))?0:false
                """
              )

Having the parser is the first half of the battle. This answer continues on to show how to attach classes to the various parsed terms - in that case it was to evaluate the result, but for you, you'll probably want to do something like implement a as_jsonlogic() method to these classes to emit equivalent forms for the JsonLogic format.

EDIT:

Ok, that may not have been that helpful to just show you the parser. So here is the parser with the added classes, and their respective as_jsonlogic() methods.

import pyparsing as pp
ppc = pp.common

bool_constant = pp.oneOf("true false")
integer = ppc.integer()
ident = ppc.identifier()
qs = pp.quotedString()

class Node:
    def __init__(self, tokens):
        self._tokens = tokens
        self.assign_vars()

    def assign_vars(self):
        pass

    def as_jsonlogic(self) -> str:
        raise NotImplementedError()

class Verbatim(Node):
    def as_jsonlogic(self) -> str:
        return str(self._tokens[0])

class Identifier(Node):
    def as_jsonlogic(self) -> str:
        return f'{{ "var": "{self._tokens[0]}" }}'

class Comparison(Node):
    def assign_vars(self):
        self.oper1, self.operator, self.oper2 = self._tokens[0]

    def as_jsonlogic(self) -> str:
        return f'{{ "{self.operator}" : [ {self.oper1.as_jsonlogic()}, {self.oper2.as_jsonlogic()} ]  }}'

class Ternary(Node):
    def assign_vars(self):
        self.condition, _, self.true_value, _, self.false_value = self._tokens[0]

    def as_jsonlogic(self) -> str:
        return f'{{ "if" : [ {self.condition.as_jsonlogic()}, {self.true_value.as_jsonlogic()}, {self.false_value.as_jsonlogic()} ]  }}'

# add the classes a parse actions, so that each expression gets converted to a Node subclass instance
qs.add_parse_action(Verbatim)
integer.add_parse_action(Verbatim)
bool_constant.add_parse_action(Verbatim)
ident.add_parse_action(Identifier)

operand = qs | integer | bool_constant | ident

comparison_operator = pp.oneOf("< > >= <=")
eq_operator = pp.oneOf("== !=")

# add parse actions to each level of the infixNotation    
expr = pp.infixNotation(operand,
                        [
                            (comparison_operator, 2, pp.opAssoc.LEFT, Comparison),
                            (eq_operator, 2, pp.opAssoc.LEFT, Comparison),
                            (('?', ':'), 3, pp.opAssoc.RIGHT, Ternary),
                        ])

# use runTests to run some tests, with a post_parse function
# to call as_jsonlogic() on the parsed result
expr.runTests("""\
    "Y"
    false
    100
    var001
    (var001 == 100)
    ((var001 == "Y"))?1:((var001 == "N"))?0:false
    """, post_parse=lambda s, r: r[0].as_jsonlogic())

Prints:

"Y"
"Y"

false
false

100
100

var001
{ "var": "var001" }

(var001 == 100)
{ "==" : [ { "var": "var001" }, 100 ]  }

((var001 == "Y"))?1:((var001 == "N"))?0:false
{ "if" : [ { "==" : [ { "var": "var001" }, "Y" ]  }, 1, { "if" : [ { "==" : [ { "var": "var001" }, "N" ]  }, 0, false ]  } ]  }

I'll leave the pretty indentation to you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文