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

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)";

tn文本分析语言(四) 实现自然语言计算器的更多相关文章

  1. 重磅开源:TN文本分析语言

    tn是desert(沙漠之鹰)和tan共同开发的一种用于匹配,转写和抽取文本的语言(DSL).并为其开发和优化了专用的编译器.基于递归下降方法和正则表达式,能解析自然文本并转换为树和字典,识别时间,地 ...

  2. tn文本分析语言(二) 基本语法

    tn是desert和tan共同开发的一种用于匹配,转写和抽取文本的语言.解释器使用Python实现,代码不超过1000行. 本文主要介绍tn的基本语法.高级内容可以参考其他篇章.使用这样的语法,是为了 ...

  3. tn文本分析语言(三):高级语法

    标签(空格分隔): 未分类 高级操作 1.脚本表达式 用双引号包含的脚本被称为脚本表达式,目前支持嵌入Python. 脚本表达式只能在顺序表达式中使用.代码可以在三个位置存在: |位置|功能|例子| ...

  4. 重磅︱R+NLP:text2vec包——New 文本分析生态系统 No.1(一,简介)

    每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 词向量的表示主流的有两种方式,一种当然是耳熟能 ...

  5. Solr:文本分析

    文本分析时搜索引擎的核心工作之一,对文本包含许多处理步骤,比如:分词.大写转小写.词干化.同义词转化等.简单的说,文本分析就说将一个文本字段的值转为一个一个的token,然后被保存到Lucene的索引 ...

  6. LinkedIn文本分析平台:主题挖掘的四大技术步骤

    作者 Yongzheng (Tiger) Zhang ,译者 木环 ,本人只是备份一下.. LinkedIn前不久发布两篇文章分享了自主研发的文本分析平台Voices的概览和技术细节.LinkedIn ...

  7. R软件中 文本分析安装包 Rjava 和 Rwordseg 傻瓜式安装方法四部曲

    这两天,由于要做一个文本分析的内容,所以搜索了一天R语言中的可以做文本分析的加载包,但是在安装包的过程,真是被虐千百遍,总是安装不成功.特此专门写一篇博文,把整个心塞史畅快的释放一下. ------- ...

  8. 用R进行文本分析初探——以《红楼梦》为例

    一.写在前面的话~ 刚吃饭的时候同学问我,你为什么要用R做文本分析,你不是应该用R建模么,在我和她解释了一会儿后,她嘱咐我好好写这篇博文,嗯为了娟儿同学,细细说一会儿文本分析. 文本数据挖掘(Text ...

  9. Linux文本分析命令awk的妙用

    基本用法 awk是一个强大的文本分析工具,简单来说awk就是把文件逐行读入,(空格,制表符)为默认分隔符将每行切片,切开的部分再进行各种分析处理 awk命令格式如下 awk [-F field-sep ...

随机推荐

  1. JavaScript-String基础知识

    1.字符串可以0个或多个字符串放在一起:     " ' '    ".'""' . "\"\""       2.写法 ...

  2. Ubuntu14.10搭建C++开发环境

    方法一:1、安装Eclipsesudo apt-get install eclipse2、安装Eclipse CDTsudo apt-get install eclipse-cdt3、安装Autoto ...

  3. JavaScript数组去重的几种方法

    这个老问题,网上普遍都有了,为什么要再写一遍呢,主要是为了记个笔记... 遍历时搜索结果数组 思路很明确,如下 新建一个数组存放结果 循环遍历原数组,对于每一个元素,在结果数组中搜索是否存在 若不存在 ...

  4. Ibatis 使用心得

    (1)建表语句 sqlMap: <statement id="createTable" parameterClass="String" > $sql ...

  5. Unity3d使用高通Vuforia发布IOS工程不支持64位的一些解决办法

    1.将Unit升级至4.6.x或5.0.x,将Vuforia差距升级到最新版本(vuforia-unity-mobile-android-ios-4-0-105 ) 2.平台Other Setting ...

  6. 深入NSQ 之旅[转载]

    介绍 NSQ是一个实时的分布式消息平台.它的设计目标是为在多台计算机上运行的松散服务提供一个现代化的基础设施骨架.这篇文章介绍了 基于go语言的NSQ的内部架构,它能够为高吞吐量的网络服务器带来 性能 ...

  7. 剑指Offer面试题:16.合并两个排序的链表

    PS:这也是一道出镜率极高的面试题,我相信很多童鞋都会很眼熟,就像于千万人之中遇见不期而遇的人,没有别的话可说,唯有轻轻地问一声:“哦,原来你也在这里? ” 一.题目:合并两个排序的链表 题目:输入两 ...

  8. Hybrid App移动应用开发初探

    一.移动App类型及其优缺点 1.1 Native App Native App(原生App)是用原生语言(Object-C/Java/C#/....)开发,用户需要下载安装的手机应用. 优点是 可以 ...

  9. 推荐:图片轮播插件Nivo Slider

          因为项目需要一款切换样式多一些的轮播插件,不经意找到了NivoSlider,非常好用,比bootstrap要好用,而且样式丰富.值得注意的是,这款插件是在MIT协议下免费的.        ...

  10. 关于新书《修炼之道:.NET开发要点精讲》的各种说明

    索引 新书介绍 新书封面 新书目录 试读章节 原稿试读 网购地址 规格参数 反馈方式 一些感谢 附加说明 1.新书介绍 从2013年年底到2014年9月,历时将近10个月,这本书终于看到了“出版发行” ...