工作中遇到一个小问题,就是要做一个类似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. JS空数组的判断

    前言 最近在做一个mini项目,被大神各种鄙视,基础知识确实是不扎实,加油加油.好了,不多废话,抽空写写遇到的两个知识点,就记录下来,写博客还是能帮忙整理记录的,不然过了就忘记了. input监听值改 ...

  2. C#入门篇-4:使用运算符

    using System; using System.Text; using System.Collections; using System.Collections.Generic; using S ...

  3. thinkphp3.2.3多图上传并且生成多张缩略图

    html部分 <!DOCTYPE html><html><head><meta http-equiv="Content-Type" con ...

  4. c#委托使用

    public class StepArgs : EventArgs { public int m_IMax = 0; public int m_IStep = 0; public string m_S ...

  5. oracle存储过程、声明变量、for循环

    oracle存储过程.声明变量.for循环  1.创建存储过程 create or replace procedure test(var_name_1 in type,var_name_2 out t ...

  6. 星际战争(bzoj 3993)

    Description 3333年,在银河系的某星球上,X军团和Y军团正在激烈地作战.在战斗的某一阶段,Y军团一共派遣了N个巨型机器人进攻X军团的阵地,其中第i个巨型机器人的装甲值为Ai.当一个巨型机 ...

  7. Reactor Cooling(ZOJ 2314)

    题意: 给n个点,及m根pipe,每根pipe用来流躺液体的,单向的,每时每刻每根pipe流进来的物质要等于流出去的物质,要使得m条pipe组成一个循环体,里面流躺物质. 并且满足每根pipe一定的流 ...

  8. Mysql EXISTS NOT EXISTS

    SELECT c.CustomerId, CompanyName FROM Customers c WHERE EXISTS( SELECT OrderID FROM Orders o WHERE o ...

  9. SPOJ QTREE Query on a tree V

    You are given a tree (an acyclic undirected connected graph) with N nodes. The tree nodes are number ...

  10. div切换 div轮换显示

    原文发布时间为:2009-05-10 -- 来源于本人的百度文章 [由搬家工具导入] <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Tran ...