工作中遇到一个小问题,就是要做一个类似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. 48、android代码架构总结

    之前是按功能模块进行分类,现在随着功能模块越来越多,代码层次不再清晰,所以修改了工程结构: 之前: 经过修改现在: 1.更严谨的遵循mvc架构 bean目录存放的是数据模型 ui存储的是activit ...

  2. Android TextWatcher的使用方法(监听ExitText的方法)

    我做了一个查询单词的简单app, 当在EditText中输入单词的时候,点击lookup,则在TextView区域显示出该单词的意思,当EditText中没有任何字符时,显示"word de ...

  3. php字符串 函数

    strtolower()//字符串转化小写的字母 $str="abcdEfG";$s=strtolower($str); 输出:abcdefg; strtoupper();字符串转 ...

  4. Redis 配置登录密码

    1. 通过配置文件进行配置 打开 redis.conf,找到 #requirepass foobared 去掉行前的注释,并修改密码为所需的密码,保存文件 重启redis sudo service r ...

  5. How Ironic Inspector Works

    翻译官网概述. 操作员将节点注册为Ironic,例如 通过openstack baremetal CLI命令. 电源管理认证应该在这一步提供给Ironic. 如节点状态所述,节点被置于正确的自省状态. ...

  6. web 大规模并发访问的解决方案

    电商的秒杀和抢购,对我们来说,都不是一个陌生的东西.然而,从技术的角度来说,这对于Web系统是一个巨大的考验.当一个Web系统,在一秒钟内收到数以万计甚至更多请求时,系统的优化和稳定至关重要.这次我们 ...

  7. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛

    拖了好久了 链接:https://www.nowcoder.com/acm/contest/90/A来源:牛客网 跳台阶 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K, ...

  8. 【bzoj3687】简单题 背包dp+STL-bitset

    题目描述 小呆开始研究集合论了,他提出了关于一个数集四个问题:1.子集的异或和的算术和.2.子集的异或和的异或和.3.子集的算术和的算术和.4.子集的算术和的异或和.目前为止,小呆已经解决了前三个问题 ...

  9. linux服务器上设置多主机头,设置多web站点

    假设VPS的IP是58.130.17.168,有两个域名指向该IP,分别是domain1.com, domain2.com, 修改/etc/httpd/conf/httpd.conf,在文件的最后加入 ...

  10. BZOJ3462 DZY Loves Math II 【多重背包 + 组合数】

    题目 输入格式 第一行,两个正整数 S 和 q,q 表示询问数量. 接下来 q 行,每行一个正整数 n. 输出格式 输出共 q 行,分别为每个询问的答案. 输入样例 30 3 9 29 1000000 ...