python实现计算器代码 博客园_tn文本分析语言(四) 实现自然语言计算器

tn是desert和tan共同开发的一种用于匹配,转写和抽取文本的语言。解释器使用Python实现,代码不超过1000行。

前言

本文将利用引擎实现一个自然语言计算器,支持加减乘除和平方的计算。如下面的测试样例:

三平方加上四平方

如果2乘以3大于4的平方且3>8,那么输出5+4,否则输出12

如果今天下雨,则发送微博

3.4的7次方加上五分之一

3.4*2.7

二百八十除以五分之一

三点五乘以三十七

二十七+15*15

十四点五的平方加上八十三除以三点五

基本的思路,是将整个文本,转换为一个Python的表达式,传递给Python的eval函数执行。这是一种取巧的办法,如果需要,可以修改引擎,实现自定义的脚本解析器。

运算符实现

下面的代码定义了计算符,非常容易理解:

#%Include% Rules/cnext

add = (/加上?|\+|+/ : /+/) ;

sub = (/减去?|\-|-/ : /-/);

mul = (/乘以?|\*|×/ : /*/);

div = (/除以?|/|÷/ : ///);

pow2 = (/的?平方/ : /**2/);

pow3 = (/的?立方/ : /**3/);

pown= (/的?/ : //) $(digit) (/次方/ : /**/) : $3 $2 $1;

divpow = $(digit) $(divpow0) $(digit) ;

powx= $(pow2) | $(pow3) | $(pown);

pow = $(digit) $(powx);

#%Include% Rules/cnext 引入了外部的一个规则文件,这个文件定义了中文和数字的表达方法。因此在本规则中,可直接引用cnext文件中定义的规则。

顺便指出,只要保证规则名称一致,通过更换为英语或其他语言的数字表达,就可以在不修改本脚本的情况下方便地让规则支持其他语言的计算功能

逻辑运算符

or = (/或/ : / or /);

and = (/且/ : / and /);

not = (/不是/ : / not /);

equal = (/等于|=/ : /=/);

bigger = (/大于|>/ : />/);

less = (/小于| :/);

noequal = (/不等于/: /!=/);

值得一提的是,我们将逻辑转换成了or and 和not, 这是为了能够转写

运算符组合

addsub0= $(add) | $(sub) ;

logic0 =$(or) | $(and) ;

divpow0 = $(mul) | $(div);

equalcheck = $(bigger) |$(less) | $(noequal);

operator= $(addsub0) | $(equalcheck) | $(logic0);

非终结符和终结符

低优先级的表达式可以表示如下:

addsub= $(noterminator) $(operator) $(noterminator);

由于乘除和n次方的的优先级比加减和逻辑运算符优先级高,所以我们将运算符分为两类:

终结符

terminator = $(digit) | $(ifelse) | $(pow) | $(divpow);

非终结符

#%Order% 28

noterminator = $(terminator) : "eval(m.rstr)" | $(addsub) : "eval(m.rstr)";

此处需要解释脚本的含义,

m在此处代指前面匹配的实体

m.rstr为m的转写后的字符串

m.mstr为m匹配的字符串

eval是引擎内置的函数,代指对转写后的字符串求值。

例子

三平方加上四平方

匹配路径如下

TODO

最后eval(32+42),结果为5

无法消除的左递归

如果希望支持计算类似'3加5的和乘以3'的表达式,那么terminator表达式需要这样写:

terminator = $(digit) | $(ifelse) | $(pow) | $(divpow) | $(function)

| $(noterminator) $(add) $(noterminator) $(addresult)

| $(noterminator) $(sub) $(noterminator) $(subresult);

但是,注意第二条子表达式

$(noterminator) $(add) $(noterminator) $(addresult)

$(noterminator)又引用了terminator,因此会导致无穷递归。

目前还没有找到合适的方法解决这个问题。

完整的代码

#计算引擎

#尝试解决 三点五乘以八点三的功能

#%Include% Rules/cnext

add = (/加上?|\+|+/ : /+/) ;

sub = (/减去?|\-|-/ : /-/);

mul = (/乘以?|\*|×/ : /*/);

div = (/除以?|/|÷/ : ///);

pow2 = (/的?平方/ : /**2/);

pow3 = (/的?立方/ : /**3/);

pown= (/的?/ : //) $(digit) (/次方/ : /**/) : $3 $2 $1;

result= (/的?结果/);

addresult0= (/的?和/);

subresult0= (/的?差/);

addresult = $(result) $(addresult0);

subresult = $(result) $(subresult0);

addsub0= $(add) | $(sub) ;

logic0 =$(or) | $(and) ;

divpow0 = $(mul) | $(div);

equalcheck = $(bigger) |$(less) | $(noequal);

operator= $(addsub0) | $(equalcheck) | $(logic0);

divpow = $(digit) $(divpow0) $(digit) ;

powx= $(pow2) | $(pow3) | $(pown);

pow = $(digit) $(powx);

#functions

print = (/打印/ : /print/);

send = (/发送/ : /send/);

functions = $(print) | $(send);

function = $(functions) $(noterminator) : "invoke(m[0].rstr,m[1].rstr)";

addsub= $(not) $(noterminator)

| $(noterminator) $(operator) $(noterminator);

terminator = $(digit) | $(ifelse) | $(pow) | $(divpow) | $(function);

#暂时无法分析 3加5的和乘以3,因为会造成循环递归,从左向右推导不可行

# | ) $(add) $(noterminator) $(addresult)

# | $(noterminator) $(sub) $(noterminator) $(subresult);

#%Order% 28

noterminator = $(terminator) : "eval(m.rstr)" | $(addsub) : "eval(m.rstr)";

or = (/或/ : / or /);

and = (/且/ : / and /);

not = (/不是/ : / not /);

equal = (/等于|=/ : /=/);

bigger = (/大于|>/ : />/);

less = (/小于| :/);

noequal = (/不等于/: /!=/);

ifelse = (/如果/) $(vu) (/,那么/) $(noterminator) (/,否则/) $(noterminator) : "check(m[1].rstr,m[3].rstr,m[5].rstr)";

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值