tn文本分析语言(四) 实现自然语言计算器
2016-04-06 21:07
387 查看
tn是desert和tan共同开发的一种用于匹配,转写和抽取文本的语言。解释器使用Python实现,代码不超过1000行。
github地址:https://github.com/ferventdesert/tnpy
基本的思路,是将整个文本,转换为一个Python的表达式,传递给Python的eval函数执行。这是一种取巧的办法,如果需要,可以修改引擎,实现自定义的脚本解析器。
顺便指出,只要保证规则名称一致,通过更换为英语或其他语言的数字表达,就可以在不修改本脚本的情况下方便地让规则支持其他语言的计算功能
值得一提的是,我们将逻辑转换成了or and 和not, 这是为了能够转写
由于乘除和n次方的的优先级比加减和逻辑运算符优先级高,所以我们将运算符分为两类:
终结符
非终结符
此处需要解释脚本的含义,
m在此处代指前面匹配的实体
m.rstr为m的转写后的字符串
m.mstr为m匹配的字符串
eval是引擎内置的函数,代指对转写后的字符串求值。
匹配路径如下
TODO
最后eval(32+42),结果为5
但是,注意第二条子表达式
目前还没有找到合适的方法解决这个问题。
github地址:https://github.com/ferventdesert/tnpy
前言
本文将利用引擎实现一个自然语言计算器,支持加减乘除和平方的计算。如下面的测试样例:三平方加上四平方 如果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)";
相关文章推荐
- The first day of HTML
- 如何让图片在垂直方向与 div的底部对齐 水平居中
- Android 用代码实现防打扰【能够屏蔽电话和短信】
- Android实现修改状态栏颜色
- node.js中如何使用mongodb数据库
- CF-631-.Interview-水题
- 手机访问网站自动跳转到手机版
- 20160406javaweb 之JDBC简单案例
- Android Scroll分析
- mysql账号增删改、数据导入导出命令举例
- 基于C++11的事件驱动框架
- PHP笔记
- RecyclerView的使用(3种视图切换)
- react native android使用react-native-tab-navigator来做底部导航tabbar(2)一个坑:navigator
- 去掉字符串中连续出现k个0的子串
- HDU 1087 Super Jumping! Jumping! Jumping!
- c++primer(第五版) 第十四章 重载运算与类型转换习题答案
- 数据结构-----栈的实现
- python中关于序列化问题
- C++走向远洋——30(六周,项目一1.0)