工作中遇到一个小问题,就是要做一个类似excel那种的公式的东西,就是A0+A1*B0那样的公式,然后得出结果。

首先,分析。

这不是计算器,计算器要比这个简易,计算器是所按即所得,即你点击+-之类的按钮时候,你的数字已经确认了,你所要做的只是转换一下string和decimal而已。

比如1+2*(2+4)/4-1

如果再算上幂运算,我打不出来幂运算的符号,尴尬。

我们可以这么写,比如,遇到的第一个数字是1,那么定义一个变量firnum=1  第一个符号是+,定义一个变量 mark=+,第二个数字是2,顶一个一个变量secnum=2,第二个符号是*,这时候进行判断,因为*/比加减的运算级别高,要先算乘除,所以,这里1和+要缓存起来,继续往下走,然后计算(),得出()内的数字是6,这时候先运算2*6,然后遇到/,计算12/4,再往后走,遇到-,这时候+-的运算级别一样,则开始运算之前的1和+,然后依次运算,最后得出结果。

怎么说呢,我们姑且认为这是一个方法吧,姑且认为,这么辛苦了,写了这么多代码,能进行四则运算,还挺正确,也不容易,没有功劳也有苦劳。

        public decimal CalcRet(string str)
{
//第一个数字
string firStr = string.Empty;
decimal firNum = 0m; //第二个数字;
string secStr = string.Empty;
decimal secNum = 0m; //temp数字
string tempStr = string.Empty; //当前计算符号
char curMark = '!';
//结果
decimal result = 0m; //上一个符号
char lastMark = '!'; for (int i = ; i < str.Length; i++)
{
char c = str[i]; //判断如果是数字和.
if (( < c && c < ) || c == '.')
{
//除却第一次是第一个数字需要转换,以后都是第一个和第二个进行累加
if (curMark == '!')
{
firStr += c;
}
else
{
if (curMark == '+' || curMark == '-')
{
secStr += c;
}
else if (curMark == '*' || curMark == '/')
{
if (lastMark == '+' || lastMark == '-')
{
tempStr += c;
}
else
{
secStr += c;
}
}
} continue;
} if (firStr != "")
{
decimal.TryParse(firStr, out firNum);
firStr = "";
} if (c == '+' || c == '-' || c == '*' || c == '/')
{
switch (curMark)
{
case '+':
if (secStr != "" && tempStr != "")
{
secNum = OperCalc(curMark, secNum, tempStr);
firNum = firNum + secNum;
secStr = "";
tempStr = "";
} if (c == '*' || c == '/')
{
lastMark = curMark;
curMark = c;
break;
} if (secStr == "") continue; firNum = OperCalc(curMark, firNum, secStr);
curMark = c;
lastMark = c;
secStr = "";
break;
case '-':
if (secStr != "" && tempStr != "")
{
secNum = OperCalc(curMark, secNum, tempStr);
firNum = firNum - secNum;
secStr = "";
tempStr = "";
} if (c == '*' || c == '/')
{
lastMark = curMark;
curMark = c;
break;
} if (secStr == "") continue; firNum = OperCalc(curMark, firNum, secStr);
curMark = c;
lastMark = c;
secStr = "";
break;
case '*': if (lastMark != '!' && tempStr != "")
{
secNum = OperCalc(curMark, secStr, tempStr);
secStr = secNum.ToString();
tempStr = ""; }
else
{
firNum = OperCalc(curMark, firNum, secStr);
secStr = "";
curMark = c;
break;
} if (c == '+' || c == '-')
{
if (lastMark != '!')
{
firNum = OperCalc(lastMark, firNum, secNum);
secStr = "";
tempStr = "";
}
} curMark = c;
break;
case '/': if (lastMark != '!' && tempStr != "")
{
secNum = OperCalc(curMark, secStr, tempStr);
secStr = secNum.ToString();
tempStr = "";
}
else
{
firNum = OperCalc(curMark, firNum, secStr);
secStr = "";
curMark = c;
break;
} if (c == '+' || c == '-')
{
if (lastMark != '!')
{
firNum = OperCalc(lastMark, firNum, secNum);
secStr = "";
tempStr = "";
}
} curMark = c;
break;
case '(':
break;
case ')':
break;
default:
curMark = c;
if (c == '+' || c == '-')
lastMark = c;
break;
}
}
else if (c == '(')
{
int temp = ;
for (int j = i + ; j < str.Length; j++)
{
var k = str[j];
if (k == '(')
{
temp++;
}
else if (k == ')')
{
temp--;
} if (temp == )
{
temp = j - i - ;
}
} var kh = CalcRet(str.Substring(i + , temp));
if (lastMark != '!')
{ if (secStr != "")
{
tempStr = kh.ToString();
}
else
{
secNum = kh;
secStr = kh.ToString();
}
}
else
{
if (i == )
{
firNum = kh;
}
else
{
secNum = kh;
secStr = kh.ToString();
}
} i += temp + ;
} }
if (tempStr != "")
{
secNum = OperCalc(curMark, secStr, tempStr);
secStr = secNum.ToString();
result = OperCalc(lastMark, firNum, secStr);
}
else
{
result = OperCalc(curMark, firNum, secStr);
}
return result; } decimal OperCalc(char mark, string fir, string sec)
{
decimal a, b;
decimal.TryParse(fir, out a);
decimal.TryParse(sec, out b);
switch (mark)
{
case '+':
return a + b;
case '-':
return a - b;
case '*':
return a * b;
case '/':
return a / b;
default:
return 0m;
}
} decimal OperCalc(char mark, decimal fir, string sec)
{
decimal b;
decimal.TryParse(sec, out b);
switch (mark)
{
case '+':
return fir + b;
case '-':
return fir - b;
case '*':
return fir * b;
case '/':
return fir / b;
default:
return 0m;
}
} decimal OperCalc(char mark, decimal fir, decimal sec)
{
switch (mark)
{
case '+':
return fir + sec;
case '-':
return fir - sec;
case '*':
return fir * sec;
case '/':
return fir / sec;
default:
return 0m;
}
}

对,就是这种写法。

在我看来,这么写的代码,真的只是一堆垃圾,我不是针对谁,我是说写成这样的逻辑,它就是垃圾,连没毕业的大学生都不如。

比如,如果加幂运算如果加mod怎么办,我就问你怎么办?

继续判断?

写不死你!

然后,我们可以换个思路。

所谓运算,不过是两个数字和一个符号之间故事,抱歉,我觉得一对一那种男女关系不适用于这里,开个玩笑,呵呵!强行尬聊~

1+2  是1,2 两个数字和+之间的运算

1+2+3*(4+5),是12345数字和四个符号进行的运算,至于括号,我们是不是可以把括号当成一个递归?就是4+5当成一个递归,调用同一个函数,返回一个结果就行了

也就是说,数字永远比符号多一个

我们是不是可以这么想。

list1 ={1,2,3,4,5}

list2={+,+,*,(+)}

第一次运算后

list1 ={1,2,3,9}

list2={+,+,*}

按照优先级,我们可先计算*

得到

list1 ={1,2,3,9}{1,2,27}

list2={+,+,*}{+,+}

删掉*和最后的9,同时删掉一个符号和一个数字,得到

list1 ={1,2,27}

list2={+,+}

继续

list1 ={3,27}

list2={+}

再继续

list1 ={30}

list2={}

最后就剩下一个数字,好,计算完毕

public class CalcOperation
{
/// <summary>
/// 计算字符串解析表达式 1+2(2*(3+4))
/// </summary>
/// <param name="str">传入的字符串</param>
/// <returns>计算得到的结果</returns>
public decimal CalcStr(string str)
{
decimal num = 0m;
//数字集合
List<decimal> numList = new List<decimal>();
//操作符集合
List<Operation> operList = new List<Operation>();
string strNum = "";
for (int i = ; i < str.Length; i++)
{
char c = str[i]; //判断如果是数字和.
if (( < c && c < ) || c == '.')
{
strNum += c; if (i == str.Length - )
{
if (!string.IsNullOrEmpty(strNum))
{
decimal.TryParse(strNum, out num);
numList.Add(num);
strNum = "";
}
}
continue;
}
else if (c == '(')
{
int temp = ;
for (int j = i + ; j < str.Length; j++)
{
var k = str[j];
if (k == '(')
{
temp++;
}
else if (k == ')')
{
temp--;
} if (temp == )
{
temp = j - i - ;
}
} strNum = str.Substring(i + , temp);
numList.Add(CalcStr(strNum));
strNum = "";
i += temp + ;
}
else
{
if (!string.IsNullOrEmpty(strNum))
{
decimal.TryParse(strNum, out num);
numList.Add(num);
strNum = "";
} if (c == '+')
{
operList.Add(new AddOperation());
}
else if (c == '-')
{
operList.Add(new SubOperation());
}
else if (c == '*')
{
operList.Add(new MultipOperation());
}
else if (c == '/')
{
operList.Add(new DivOperation());
}
else if (c == '%')
{
operList.Add(new ModOperation());
}
else
{
operList.Add(null);
}
}
} List<int> tempOrder = new List<int>();
operList.ForEach(w =>
{
if (!tempOrder.Contains(w.PrioRity))
{
tempOrder.Add(w.PrioRity);
} }); tempOrder.Sort();
for (int t = ; t < tempOrder.Count; t++)
{
for (int i = ; i < operList.Count; i++)
{
if (operList[i].PrioRity == tempOrder[t])
{
numList[i] = operList[i].OperationResult(numList[i], numList[i + ]);
numList.RemoveAt(i + );
operList.RemoveAt(i);
i--;
}
}
} if (numList.Count == ) return numList[]; return 0m;
} public class Operation
{
protected int priority = ;
/// <summary>
/// 优先级
/// </summary>
public virtual int PrioRity
{
get
{
return priority;
}
set
{
priority = value;
}
} public virtual decimal OperationResult(decimal a, decimal b)
{
return 0m;
}
} public class AddOperation : Operation
{
public override decimal OperationResult(decimal a, decimal b)
{
return a + b;
}
} public class SubOperation : Operation
{
public override decimal OperationResult(decimal a, decimal b)
{
return a - b;
}
} public class MultipOperation : Operation
{
public override int PrioRity
{
get
{
return ;
}
} public override decimal OperationResult(decimal a, decimal b)
{
return a * b;
}
} public class DivOperation : Operation
{
public override int PrioRity
{
get
{
return ;
}
}
public override decimal OperationResult(decimal a, decimal b)
{
return a / b;
}
} public class ModOperation : Operation
{
public override int PrioRity
{
get
{
return ;
}
}
public override decimal OperationResult(decimal a, decimal b)
{
return a % b;
}
} }
PrioRity这个是优先级,我比较懒,就从99往上了
但是这样真的很明了啊,而且可以随时添加新的算法,简直了 我想说的是,能简便的尽量简便,能通运的尽量通用,自己看的舒服,别人看的也舒服,是不是~

C# 计算一串字符串算法的更多相关文章

  1. iOS:使用莱文斯坦距离算法计算两串字符串的相似度

    Levenshtein:莱文斯坦距离 Levenshtein的经典算法,参考http://en.wikipedia.org/wiki/Levenshtein_distance的伪代码实现的,同时参考了 ...

  2. MD5算法【计算文件和字符串的MD5值】

    1. MD5算法是一种散列(hash)算法(摘要算法,指纹算法),不是一种加密算法(易错).任何长度的任意内容都可以用MD5计算出散列值.MD5的前身:MD2.MD3.MD4.介绍工具:CalcMD5 ...

  3. Levenshtein Distance + LCS 算法计算两个字符串的相似度

    //LD最短编辑路径算法 public static int LevenshteinDistance(string source, string target) { int cell = source ...

  4. boost字符串算法

    boost::algorithm简介 2007-12-08 16:59 boost::algorithm提供了很多字符串算法,包括: 大小写转换: 去除无效字符: 谓词: 查找: 删除/替换: 切割: ...

  5. 基础数据结构-串-KMP算法

    KMP算法用于模式串字符匹配,因为没有提前预习,上课时听得云里雾里,后来回去看了一晚上,翻了一些网上的讲解才理解了.我简单讲一下,我们在一串字符串A里搜索匹配另一段字符串B时,思路最简单方法的就是从第 ...

  6. 利用编辑距离(Edit Distance)计算两个字符串的相似度

    利用编辑距离(Edit Distance)计算两个字符串的相似度 编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数.许可 ...

  7. python-Levenshtein几个计算字串相似度的函数解析

    linux环境下,没有首先安装python_Levenshtein,用法如下: 重点介绍几个该包中的几个计算字串相似度的几个函数实现. 1. Levenshtein.hamming(str1, str ...

  8. 【字符串算法2】浅谈Manacher算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最 ...

  9. 【字符串算法3】浅谈KMP算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...

随机推荐

  1. 设计模式之第18章-观察者模式(Java实现)

    设计模式之第18章-观察者模式(Java实现) 话说曾小贤,也就是陈赫这些天有些火,那么这些明星最怕的,同样最喜欢的是什么呢?没错,就是狗仔队.英文的名字比较有意思,是paparazzo,这一说法据说 ...

  2. Python框架之Django学习笔记(十三)

    Django站点管理(续1) 上次介绍了Django的站点管理的一些基础知识,这次再来深入了解一下Django的站点管理. Admin是如何工作的: 在幕后,管理工具是如何工作的呢? 其实很简单. 当 ...

  3. jmeter将上一个请求的结果作为下一个请求的参数——使用正则提取器

    转自:http://www.cnblogs.com/0201zcr/p/5089620.html 在压力测试的时候,经常要将几个流程串联起来才能将程序测试通过.如:我现在用户首先要登录,获得我登录的凭 ...

  4. 菜鸟之路——机器学习之非线性回归个人理解及python实现

    关键词: 梯度下降:就是让数据顺着梯度最大的方向,也就是函数导数最大的放下下降,使其快速的接近结果. Cost函数等公式太长,不在这打了.网上多得是. 这个非线性回归说白了就是缩小版的神经网络. py ...

  5. 牛客多校第六场C

    一个数很大,并不能预处理,所以要进行公式变换,存前一个的值就好 #include <bits/stdc++.h> using namespace std; typedef long lon ...

  6. 什么是虚假唤醒 spurious wakeup

    解释一下什么是虚假唤醒? 说具体的例子,比较容易说通. pthread_mutex_t lock; pthread_cond_t notempty; pthread_cond_t notfull; v ...

  7. 微信小程序--微信小程序tabBar不显示:缺少文件,错误信息:error:iconPath=

    1.list中的第一个tab的地址必须定义在pages 中 2.pagePath的地址一定要正确 正确写法是: "tabBar": { "color": &qu ...

  8. win7分盘(复制)

    1/10 右击“计算机”选择“管理” 2/10 打开管理之后点击“磁盘管理器”,在想要新建磁盘的分区上右击,点击“压缩卷” 3/10 在“输入压缩空间量”后面输入需要新建磁盘的大小,输入的单位为MB( ...

  9. s if标签

    字符串N一定要用“”双引号包含,从test的包含则用单引号 ‘ ’,如果相反,则不能正确判断该属性是否与该字符串相等. 正确:<s:if test='activityBean.searchFor ...

  10. ruby 制作自己的gem包

    在ruby工程目录下新建一个文件:crowdSystem.gemspec.需要在lib目录下存在同一名称的ruby库文件:crowdSystem.rb