如何用Python的运算符模块编写小型DSL解析器

2 投票
2 回答
987 浏览
提问于 2025-04-16 18:47

下面是一些矩阵数据:

    A   B   C   D   E   F   G
1   89  92  18  7   90  35  60
2   62  60  90  91  38  30  50
3   59  91  98  81  67  88  70
4   20  28  31  9   91  6   18
5   80  27  66  1   33  91  18
6   82  30  47  8   39  22  32
7   14  11  70  39  18  10  56
8   98  95  84  47  28  62  99

我需要定义一个“规则”函数,这个函数可以针对每一行数据返回“真”或“假”,并且能够通过下面的断言字符串进行判断:

A=B and B=C
A>C
B>C
C>D and D<E or D>F
A+B<30
A+B<=30                # this may using "A+B<30 or A+B=30" as alternative
str(A) march regex"[2-5][0-2]" 
myfoo(A) > 100 
A in myfoo(B)
A not_in $listname
A in $listname

“A=B and B=C”为例:如果我把第一行数据传入这个规则,我希望规则返回假,因为在这种情况下这个判断是不正确的。

我的问题是:

  1. 我该如何定义一个DSL解析器,把这些“规则字符串”转换成可以使用的lambda函数,然后我可以用数据行作为参数来调用这个lambda,返回断言结果?

  2. 我注意到模块操作有很多数学函数可以重用来定义规则,我可以为这些关键词创建一个“映射器”供DSL解析器使用吗?它可能看起来像这样:

    关键词 = {"+": operation.add(), "/": operation.div(), "and": my_and_define() }

  3. 如果以上两个是可行的,我该如何在lambda和映射器中处理“A in $listname”?

谢谢你的帮助。

祝好,

KC

2 个回答

1

你的领域特定语言(DSL)的示例语法有多重要呢?最简单的方法就是使用Python的表达式语法和eval()函数。否则,你可能需要把你的形式转换成可以用eval()处理的东西。

1

像这样。

class Rule( object ):
    def __init__( self, text ):
        self.text= text
    def test( self, A, B, C, D, E, F, G ):
        return eval( self.text )

r1= Rule( "A==B" )
r2= Rule( "A==B and B==C" )
r3= Rule( "A in {listname!s}".format( listname=someList ) )

等等。

>>> r1.test( 89,  92,  18,  7,   90,  35, 60 )
False

编辑。

  • str(A) march regex"[2-5][0-2]"
  • myfoo(A) > 100
  • A 在 myfoo(B) 中

这些都是很简单的Python代码。我不明白为什么这个评论会被认为有趣或困难。

r4= Rule( "re.match( r'[2-5][0-2]', str(A) )" )
r5= Rule( "myfoo(A) > 100" )
r6= Rule( "A in myfoo(B)" )

这里有个小窍门。这个窍门就是写Python代码,然后把代码放在引号里。任何 Python代码都是合法的。

如果这些规则中的Python部分让你感到困惑,找个Python教程可能会有帮助。

撰写回答