将简单的表达式转换为 JsonLogic 格式
Convert simple expressions into JsonLogic format
使用python,我需要将表达式转换成JsonLogic格式。布尔表达式、if else/三元表达式等表达式
有什么实现方法的建议吗?
P.S。我看到我们在 Javascript 中有一个 js-to-json-logic
library。找不到它的等效 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
根据运算符优先级和括号输出
Pyparsing 的 infixNotation 方法将允许定义一元、二元和三元运算符(例如您的 expr ? true_value : false_value
操作)。此代码将解析您给定的表达式:
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
"""
)
拥有解析器是成功的前半部分。 This answer 继续展示如何将 类 附加到各种解析的术语 - 在这种情况下它是评估结果,但对你来说,你可能想要做一些事情,比如实现 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 ] } ] }
我会把漂亮的缩进留给你。
使用python,我需要将表达式转换成JsonLogic格式。布尔表达式、if else/三元表达式等表达式
有什么实现方法的建议吗?
P.S。我看到我们在 Javascript 中有一个 js-to-json-logic
library。找不到它的等效 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
根据运算符优先级和括号输出
Pyparsing 的 infixNotation 方法将允许定义一元、二元和三元运算符(例如您的 expr ? true_value : false_value
操作)。此代码将解析您给定的表达式:
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
"""
)
拥有解析器是成功的前半部分。 This answer 继续展示如何将 类 附加到各种解析的术语 - 在这种情况下它是评估结果,但对你来说,你可能想要做一些事情,比如实现 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 ] } ] }
我会把漂亮的缩进留给你。