[原创]从中文智能提示到表达式识别与计算
2009-07-29 18:23
357 查看
前言
在此处我以表达式“3+(4*(1+(1+2)))*(1+2)(3+2)”,虽然谈到是中文提示到这篇的,但是为了画图和解释方便,暂且用数字直接代替。
事实上,中文表达式到具体的值只有一步而已,那就是识别=>反射=>读属性。
通过上述表达式可以看出,一个表达式中有两个关键元素,即:操作符(operator)和操作数(operand).
对于操作符而言,常见是分为一元和二元的,对于二元操作符自然是有2个操作数的,不同操作数之间类型的不同也导致了结果的输出的不同。
还要考虑操作符的优先级顺序,因为在表达式中,优先级决定了谁优先计算,这步的实现直接导致了表达式表达意义的对与错。
所以在对一段表达式做计算前,必须要完成三个步骤
1.合法性检测=>a.是否包含未完全匹配的小括号.异常反馈及处理。
b.是否出现无意义的参量或者表达式
c.非法操作符或非法操作数
2.表达式分析=>a.是否包含有中文表达式(如果有则要进行反射取值)
b.操作符的可操作类型,操作元个数
3.操作数的类型,类型的溢出=>字符串,数值等类型的比较。
STEP1:计算单元
既然本文是写表达式识别,那么就要先从表达式存储结构开始,由下图可以看出事例表达式即将被分离成若干计算单元:
由上图可以看出,最终此表达式被简化了,那么这些操作数和操作符,都以树的结构被构建出来,因此创建了一个FCNNodes的类来存储如此的计算小单元。
[code]{
[/code]
STEP2:读取计算表达式
全匹配,从最内部开始,根据正则表达式,取一个表达式中最内部的表达式最后得到最简表达式。
最简表达式的计算符号识别,有很多的算法,此处只作为引子,会专门用一节去说明这个。
STEP3:如何计算
一个节点计算单元其目的就是为了算出Value值,所以外部只要访问这个Value自然就可以计算出来。在Value的内部,使用Oprand取找出对应的方法,Oprand是一个操作符枚举[Flags]。
到现在为止,分为两个计算类别:数值计算及逻辑计算。
数值计算的有:+-*/%
逻辑计算的有:==,>,<,!=,&&,||,>=,<=
这里只例举了一些常用的,当然你也可以自定义一些你认为比较有性格的计算符号-_-,它们的计算方式都被定义在FCNCalculater和FCNJudager。(其实当我写出来后,我发现这种组织方法并不是很好的,之后会有一些说明。)
现在用FCNJudager为例子:
[code]{
[/code]
在判断式中是以这样的步骤进行的:
1.首先根据节点单元中的操作符找到对应的操作逻辑。
2.在操作逻辑中,获取节点单元的两个子节点的Value。
3.判断返回的Value是何种类型。
外话
对于第三点特别说明一下,此处给的事例是很简单的,主要是先判断是否为int,然后在判断是否为long,最后才是string.(当然在这里考虑的方面依然是很幼稚的!)
如果是整型会有溢出,如果是一个是int,一个是string,那么就以string返回,等等这些都需要做Check,而如果在这个地方把所有的情况全部例举全,那是何等的壮观啊!!
此时,我想这些操作符的特性都限定在一个类里面,然后用一个操作符的集合去管理这些类。
在此处我以表达式“3+(4*(1+(1+2)))*(1+2)(3+2)”,虽然谈到是中文提示到这篇的,但是为了画图和解释方便,暂且用数字直接代替。
事实上,中文表达式到具体的值只有一步而已,那就是识别=>反射=>读属性。
通过上述表达式可以看出,一个表达式中有两个关键元素,即:操作符(operator)和操作数(operand).
对于操作符而言,常见是分为一元和二元的,对于二元操作符自然是有2个操作数的,不同操作数之间类型的不同也导致了结果的输出的不同。
还要考虑操作符的优先级顺序,因为在表达式中,优先级决定了谁优先计算,这步的实现直接导致了表达式表达意义的对与错。
所以在对一段表达式做计算前,必须要完成三个步骤
1.合法性检测=>a.是否包含未完全匹配的小括号.异常反馈及处理。
b.是否出现无意义的参量或者表达式
c.非法操作符或非法操作数
2.表达式分析=>a.是否包含有中文表达式(如果有则要进行反射取值)
b.操作符的可操作类型,操作元个数
3.操作数的类型,类型的溢出=>字符串,数值等类型的比较。
STEP1:计算单元
既然本文是写表达式识别,那么就要先从表达式存储结构开始,由下图可以看出事例表达式即将被分离成若干计算单元:
由上图可以看出,最终此表达式被简化了,那么这些操作数和操作符,都以树的结构被构建出来,因此创建了一个FCNNodes的类来存储如此的计算小单元。
publicclassFCNNodes
[code]{
#region构造函数
publicFCNNodes(){}
publicFCNNodes(FCNOprandoprand,FCNNodesoprn1,FCNNodesoprn2,intndeep):this(){……}
publicFCNNodes(FCNOprandoprand,FCNNodesoprn1,FCNNodesoprn2):this(oprand,oprn1,oprn2,0){……}
publicFCNNodes(FCNOprandoprand,objectvalue):this(){……}
#endregion
#region属性定义
///<summary>
///运算符
///</summary>
publicFCNOprandOprand{get;set;}
///<summary>
///子计算节点1
///</summary>
publicFCNNodesOprn1{set;get;}
///<summary>
///子计算节点2
///</summary>
publicFCNNodesOprn2{get;set;}
privateobject_value=null;
///<summary>
///本计算结点内的计算结果
///</summary>
publicobjectValue
{
set{_value=value;}
get
{
if(_value!=null)
{
return_value;
}
else
{
/**
*根据节点Oprand去找出对应的运算方法。
*/
//计算式子
if((this.Oprand&FCNOprand.CALCULATER)!=0)
{
FCNCalculaterfcnc=newFCNCalculater();
_value=fcnc.Calculater(this);
}
//判断式子
if((this.Oprand&FCNOprand.JUDAGER)!=0)
{
FCNJudagerfcnj=newFCNJudager();
_value=fcnj.Judager(this);
}
return_value;
}
}
}
///<summary>
///计算式深度
///</summary>
publicintnDeep{set;get;}
#endregion
}
[/code]
STEP2:读取计算表达式
全匹配,从最内部开始,根据正则表达式,取一个表达式中最内部的表达式最后得到最简表达式。
最简表达式的计算符号识别,有很多的算法,此处只作为引子,会专门用一节去说明这个。
STEP3:如何计算
一个节点计算单元其目的就是为了算出Value值,所以外部只要访问这个Value自然就可以计算出来。在Value的内部,使用Oprand取找出对应的方法,Oprand是一个操作符枚举[Flags]。
到现在为止,分为两个计算类别:数值计算及逻辑计算。
数值计算的有:+-*/%
逻辑计算的有:==,>,<,!=,&&,||,>=,<=
这里只例举了一些常用的,当然你也可以自定义一些你认为比较有性格的计算符号-_-,它们的计算方式都被定义在FCNCalculater和FCNJudager。(其实当我写出来后,我发现这种组织方法并不是很好的,之后会有一些说明。)
现在用FCNJudager为例子:
publicclassFCNJudager
[code]{
publicFCNJudager()
{
}
///<summary>
///判断访问器
///</summary>
///<paramname="fcnn"></param>
///<returns></returns>
publicvirtualboolJudager(FCNNodesfcnn)
{
/**
*1.找出两者共有类型,如:oprn1是int型,oprn2是string型,那么返回string。
*/
boolresult=false;
switch(fcnn.Oprand)
{
caseFCNOprand.Equals:
{
#regionEqualsLogic
result=jageEqual(fcnn);
#endregion
}
break;
caseFCNOprand.Bigthan:
{
#regionBigthanLogic
result=BigSmallThan(fcnn.Oprn1.Value,fcnn.Oprn2.Value);
#endregion
}
break;
caseFCNOprand.Smallthan:
{
#regionSmallthanLogic
result=!BigSmallThan(fcnn.Oprn2.Value,fcnn.Oprn1.Value);
#endregion
}
break;
caseFCNOprand.NoEquals:
{
#regionNoEqualsLogic
result=!jageEqual(fcnn);
#endregion
}
break;
caseFCNOprand.AND:
{
#regionANDLogic
//True&&False
if(FCNTypeChecker.Checker<bool>(fcnn.Oprn1.Value)
&&FCNTypeChecker.Checker<bool>(fcnn.Oprn2.Value))
{
result=bool.Parse(fcnn.Oprn1.Value.ToString())&&bool.Parse(fcnn.Oprn2.Value.ToString());
}
#endregion
}
break;
caseFCNOprand.OR:
{
#regionORLogic
//True||False
if(FCNTypeChecker.Checker<bool>(fcnn.Oprn1.Value)
&&FCNTypeChecker.Checker<bool>(fcnn.Oprn2.Value))
{
result=bool.Parse(fcnn.Oprn1.Value.ToString())||bool.Parse(fcnn.Oprn2.Value.ToString());
}
#endregion
}
break;
caseFCNOprand.BigthanEquals:
{
#regionBigthanEqualsLogic
if(jageEqual(fcnn)||BigSmallThan(fcnn.Oprn1.Value,fcnn.Oprn2.Value))
{
result=true;
}
#endregion
}
break;
caseFCNOprand.SmallthanEquals:
{
#regionSmallthanEqualsLogic
if(jageEqual(fcnn)||!BigSmallThan(fcnn.Oprn2.Value,fcnn.Oprn1.Value))
{
result=true;
}
#endregion
}
break;
}
returnresult;
}
///<summary>
///大小比较
///</summary>
///<paramname="value1"></param>
///<paramname="value2"></param>
///<returns></returns>
privatestaticboolBigSmallThan(objectvalue1,objectvalue2)
{
boolbresult=false;
//int->datetime->string
if(FCNTypeChecker.Checker<int>(value1.ToString())
&&FCNTypeChecker.Checker<int>(value2.ToString()))
{
bresult=int.Parse(value1.ToString())>int.Parse(value2.ToString());
}
if(FCNTypeChecker.Checker<long>(value1.ToString())
&&FCNTypeChecker.Checker<long>(value2.ToString()))
{
bresult=long.Parse(value1.ToString())>long.Parse(value2.ToString());
}
if(FCNTypeChecker.Checker<DateTime>(value1.ToString())
&&FCNTypeChecker.Checker<DateTime>(value2.ToString()))
{
bresult=(DateTime.Parse(value1.ToString()).CompareTo(DateTime.Parse(value2.ToString()))==1);
}
if(value1.ToString().CompareTo(value2.ToString())==1)
{
bresult=true;
}
returnbresult;
}
///<summary>
///相等判断
///</summary>
///<paramname="fcnn"></param>
///<returns></returns>
privatebooljageEqual(FCNNodesfcnn)
{
boolbresult=false;
if(FCNTypeChecker.Checker<int>(fcnn.Oprn1.Value.ToString())
&&FCNTypeChecker.Checker<int>(fcnn.Oprn2.Value.ToString()))
{
bresult=int.Parse(fcnn.Oprn1.Value.ToString())==int.Parse(fcnn.Oprn2.Value.ToString());
}
if(FCNTypeChecker.Checker<long>(fcnn.Oprn1.Value.ToString())
&&FCNTypeChecker.Checker<long>(fcnn.Oprn2.Value.ToString()))
{
bresult=long.Parse(fcnn.Oprn1.Value.ToString())==long.Parse(fcnn.Oprn2.Value.ToString());
}
if(fcnn.Oprn1.Value.ToString().Equals(fcnn.Oprn2.Value.ToString()))
{
bresult=true;
}
returnbresult;
}
}
[/code]
在判断式中是以这样的步骤进行的:
1.首先根据节点单元中的操作符找到对应的操作逻辑。
2.在操作逻辑中,获取节点单元的两个子节点的Value。
3.判断返回的Value是何种类型。
外话
对于第三点特别说明一下,此处给的事例是很简单的,主要是先判断是否为int,然后在判断是否为long,最后才是string.(当然在这里考虑的方面依然是很幼稚的!)
如果是整型会有溢出,如果是一个是int,一个是string,那么就以string返回,等等这些都需要做Check,而如果在这个地方把所有的情况全部例举全,那是何等的壮观啊!!
此时,我想这些操作符的特性都限定在一个类里面,然后用一个操作符的集合去管理这些类。
相关文章推荐
- [原创]通过Attribute完成中文智能提示
- 『原创』让.Net CF实现智能提示(AutoComplete)功能
- vs2010简体中文旗舰版智能感知,中文提示,英文提示变化的问题
- Ext TextField默认提示信息,并支持中文按2个长度计算
- vs2015智能提示英文改为中文
- Java OCR 图像智能字符识别技术,可识别中文
- 中文汉化vs2010下mvc4.0的智能提示
- vs2015智能提示英文改为中文
- 安装中文VS2008 SP1 后智能提示是英文的解决办法(官方解决办法)
- 3.2.5.10 识别中文的正则表达式
- 【原创】Delphi实现数学表达式的计算(逆波兰式法)-四则运算解析
- 我的VS2008,我做主(让我们的中文VS2008也支持jQuery智能提示)
- Java OCR 图像智能字符识别技术,可识别中文
- VS中智能提示无法显示中文
- CW3002F,CW3005,赛微一级代理,USB智能识别方案,现货,中文设计方案
- 安装中文VS2008 SP1 和.NETFRAMEWORK 3.5SP1后智能提示是英文的解决办法
- 3.2.5.10 识别中文的正则表达式
- Resharper6.0如何启用原VS的中文智能提示
- 黄聪:VS2017调试时提示“运行时无法计算表达式的值”
- 利用正则表达式计算含有中文的字符串长度