C#制作简单的计算器(运算级+括号+超长算式处理)
计算器做其实很简单,这里的核心算法只需要做到以下几步:(界面等请看后面)
1.分割得到的数组(字符串,用Tochararray)再拼接
2.检查(可以自己添加)
3.计算
其中核心的计算方式如下↓↓↓↓↓↓
举个例子,2*3+45,分割后就是'2','*','3','+','4','5'
然后一个for循环将"+","-","*","/"后面的数字(从上一个符号开始)一起拼接起来,最后得到的是2,*,3,+,45.
在检查一下有没有*/,并返回true和false(有,无)
这里结果肯定是true
在进入计算阶段,因为是true,所以遍历到第一个,直到第一个乘号或除号处,把列表的前一个位和后一个位相乘(如果是除法就相除),得到了6,将开始的那个数(2)变成6,再减去列表后面两个值,得到列表为6+45,最后进行加减法(如果是false,上面的乘除法就不用计算了),众所周知,一般来说一个算式它第二个总是“+”,“-”,“×”,“÷”,所以在加减计算中只要将下标为0和下标为2的数按照下标为1的符号计算即可,这里就6(下标为0),+(下标为1),45(下表为2),因为下标1的是+,所以6+45=51,得到的最后的结果就是51
如果说有括号的话,从括号(“(”)处+1的位置添加到一个新列表然后到“)”将里面的项添加到新列表里面就OK了,然后调用一下上面的算法,算出括号里的值,接着把值添加进去同时把列表后面的项删掉,重复此操作直到没有括号,最终再调用一下计算模块即可。
废话不多说直接上代码
public static double main(string get)
{
List<string> li = new List<string>();
List<int> wh = new List<int>();
bool hav;
double final;
li = Sp(get);
wh = backet(li);
hav = have(li);
if (wh.Count > 1)
{
final = ba(wh, li, hav);
}
else
{
final = calulater(li, hav);
}
return final;
}
public static List<string> Sp(string input)
{
char[] spilt = input.ToCharArray();
string num = "";
int where = 0;
bool whbr = false;
List<string> get = new List<string>();
for (int c = 0; c < spilt.Length; c++)
{
if (spilt[c] == ')')
{
for (int i = where; i < c; i++)
{
num = num + spilt[i];
}
get.Add(num);
get.Add(")");
where = c + 1;
num = "";
whbr = true;
}
else if (whbr)
{
get.Add(Convert.ToString(spilt[c]));
where = c + 1;
num = "";
whbr = false;
}
else if (spilt[c] == '+' || spilt[c] == '-' || spilt[c] == '*' || spilt[c] == '/')
{
for (int i = where; i < c; i++)
{
num = num + spilt[i];
}
get.Add(num);
switch (spilt[c])
{
case '+': get.Add("+"); break;
case '-': get.Add("-"); break;
case '*': get.Add("*"); break;
case '/': get.Add("/"); break;
}
where = c + 1;
num = "";
}
if (spilt[c] == '(')
{
switch (spilt[c])
{
case '(': get.Add("("); break;
}
where = c + 1;
}
}
num = string.Empty;
if(spilt[spilt.Length-1] != ')')
{
for (int i = where; i < spilt.Length; i++)
{
num = num + spilt[i];
}
get.Add(num);
}
return get;
}
public static List<int> backet(List<string> get)
{
int num = 0;//括号(组)的个数
List<int> where = new List<int>();
for (int i = 0; i < get.Count; i++)
{
if (get[i] == "(")
{
num = num + 1;
where.Add(i);
}
if (get[i] == ")")
{
where.Add(i);
}
}
return where;
}
public static bool have(List<string> get)
{
bool h = false;
for (int i = 0; i < get.Count; i++)
{
if (get[i] == "*" || get[i] == "/")
{
h = true;
return h;
}
}
return h;
}
public static double calulater(List<string> get, bool hav)
{
int i = 0;
double c = 0;//计算结果
bool h;
if (hav)
{
while (true)
{
i++;
if (get[i] == "*")
{
c = int.Parse(get[i - 1]) * int.Parse(get[i + 1]);
get[i - 1] = Convert.ToString(c);
get.RemoveAt(i);
get.RemoveAt(i);
i = 0;
}
else if (get[i] == "/")
{
if (int.Parse(get[i - 1]) % int.Parse(get[i + 1]) == 0)
{
c = int.Parse(get[i - 1]) / int.Parse(get[i + 1]);
get[i - 1] = Convert.ToString(c);
get.RemoveAt(i);
get.RemoveAt(i);
i = 0;
}
else
{
c = double.Parse(get[i - 1]) / double.Parse(get[i + 1]);
get[i - 1] = Convert.ToString(c);
get.RemoveAt(i);
get.RemoveAt(i);
i = 0;
}
}
h = have(get);
if (!h)
{
break;
}
c = 0;
}
c = 0;
}
if (get.Count != 1)
{
while (true)
{
if (get[1] == "+")
{
c = int.Parse(get[0]) + int.Parse(get[2]);
get[0] = Convert.ToString(c);
get.RemoveAt(1);
get.RemoveAt(1);
}
else if (get[1] == "-")
{
c = int.Parse(get[0]) - int.Parse(get[2]);
get[0] = Convert.ToString(c);
get.RemoveAt(1);
get.RemoveAt(1);
}
c = 0;
if (get.Count == 1)
{
break;
}
}
}
return int.Parse(get[0]);
}
public static double ba(List<int> b, List<string> get, bool hav)
{
List<string> li = new List<string>();
double re = 0;
int cut = 0;
int ci = b.Count / 2;
List<int> whereba = new List<int>();
whereba = b;
for (int i = 0; i < ci; i++)
{
for (int j = whereba[0] + 1; j < whereba[1]; j++)
{
li.Add(get[j]);
cut = cut + 1;
}
cut = cut + 2;
bool ha = have(li);
re = calulater(li, ha);
get[whereba[0]] = Convert.ToString(re);
for (int k = 0; k < cut - 1; k++)
{
get.RemoveAt(whereba[0] + 1);
}
li.Clear();
whereba = backet(get);
cut = 0;
}
re = calulater(get, hav);
return re;
}
注意,在这里面()必须是英文的括号,中文的括号不行!!!
这就是核心算法,当然,还要记得加上一下几段话在调用包下面
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
这些主要调用里面的List
其次就是构造界面:(c#2019,winform窗体应用)
刚开始要添加各个数字按钮,乘除号,=,清除,返回和一个textbox(建议将multiline设置为true会比较好看)
我是这么排版的,仿照的是windows自带的计算器
接着只要在每一个button(vs双击可以进入button事件)事件里添加如下
private void button7_Click(object sender, EventArgs e)
{
textBox1.Text = textBox1.Text + "1";
}
同时如果=号控件按下时则调用上面的main方法,将参数设置为textbox1.Text,找一个值储存返回值并在textbox1上面显示,如下↓↓↓↓↓↓
private void button15_Click(object sender, EventArgs e)
{
double re;
re = main(textBox1.Text);
textBox1.Text = Convert.ToString(re);
}
这样就可以了
至于删除清空的内容直接可以用string.Empty或者Remove等方法对字符串进行操作
这个算法整体比较复杂但还是OK的,由于复杂性还可能会出现一些问题,至于算式是否规范可以在button后面写相关的代码,这里给出一些相关的检验方式:
1.看看每一个+-*/前后的数字是否可以被int.Parse转换成数字(这里要用到try……catch),如果是括号则跳过
2.看看除号后下一项是否为0,这个可以在控件中防止如当除号按下时则不能按0(除非已经按了其他数字)
至于更多规定大家可以自己补充说明。
当然,在最后我也把c#计算器最新源码(命令行,非界面)2023.7.4的公布一下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace calulater
{
internal class Program
{
static void Main(string[] vs)
{
//数据创建@用户输入
int have = 0; //优先级,1代表有*/,0代表无*/
string input = Console.ReadLine();
List<string> get = new List<string>();
int re = 0; //计算最后的值
bool ch = false; //检查是否通过
int count = 0; //是否有括号以及括号个数
char[] spilt = input.ToCharArray();
string num = "";
int where = 0;
bool whbr = false;
for (int c = 0; c < spilt.Length; c++)
{
if (spilt[c] == ')')
{
for (int i = where; i < c; i++)
{
num = num + spilt[i];
}
get.Add(num);
get.Add(")");
where = c + 1;
num = "";
whbr = true;
}
else if (whbr)
{
get.Add(Convert.ToString(spilt[c]));
where = c + 1;
num = "";
whbr = false;
}
else if (spilt[c] == '+' || spilt[c] == '-' || spilt[c] == '*' || spilt[c] == '/')
{
for (int i = where; i < c; i++)
{
num = num + spilt[i];
}
get.Add(num);
switch (spilt[c])
{
case '+': get.Add("+"); break;
case '-': get.Add("-"); break;
case '*': get.Add("*"); break;
case '/': get.Add("/"); break;
}
where = c + 1;
num = "";
}
if (spilt[c] == '(')
{
switch (spilt[c])
{
case '(': get.Add("("); break;
}
where = c + 1;
}
}
num = "";
if (spilt[spilt.Length - 1] == ')')
{
for (int k = where; k < spilt.Length-1; k++)
{
num = num + spilt[k];
}
get.Add(num.ToString());
get.Add(")");
}
else
{
for (int k = where; k < spilt.Length; k++)
{
num = num + spilt[k];
}
get.Add(num.ToString());
}
//检验是否正确
ch = Check(get);
have = priority(get);
if (ch)
{
//计算
count = Brackets(get);
if (count == 0)
{
re = calulater(get, have);
}
else
{
re = calbr(get, have,count);
}
Console.WriteLine(re);
}
}
static bool Check(List<string> arr)
{
/*
* 输入值中不可有除加减乘除以及其他数字之外的内容
* 开头和结尾只能是数字
* 符号不可并存
* 除数不能为0
*/
int get = 0;
int pass = 0;
List<string> check = new List<string>(arr);
for (int i = 0; i < check.Count; i++)
{
/*
if(check[0] != "(" || check[check.Count-1] != ")")
{
if (i == 0 || i == check.Count - 1)
{
try
{
get = int.Parse(check[i]);
}
catch (Exception ax)
{
Console.WriteLine("接收到异常,发现您的开头或结尾并非数字,请规范您的算式书写:" + ax.Message);
return false;
}
}
}
*/
/*
if (check[i] == "+" || check[i] == "-" || check[i] == "*" || check[i] == "/" )
{
try
{
get = int.Parse(check[i+1]);
get = int.Parse(check[i-1]);
}
catch (Exception ex)
{
if(check[i] != "("||check[i] !=")" || check[i+1] != "(" || check[i+1] != ")" || check[i-1] != "(" || check[i-1] != ")")
{
Console.WriteLine("接收到异常,发现您的输入之中有其他字符,请规范您的算式书写:" + ex.Message);
return false;
}
}
}
*/
if ((check[i] == "+" || check[i] == "-" || check[i] == "*" || check[i] == "/") && (check[i + 1] == "+" || check[i + 1] == "-" || check[i + 1] == "*" || check[i + 1] == "/"))
{
Console.WriteLine("接收到异常,发现您的输入之中加减乘除重叠,请规范您的算式书写");
return false;
}
if (check[i] == "/")
{
get = int.Parse(check[i + 1]);
if (get == 0)
{
Console.WriteLine("接收到异常,发现您的输入之中除数为0,请规范您的算式书写");
return false;
}
}
}
return true;
}
static int priority(List<string> err) //err为列表
{
List<string> prior = new List<string>(err);
for (int i = 0;i < prior.Count; i++)
{
if (prior[i] == "*" || prior[i] == "/")
{
return 1;
}
}
return 0;
}
static int Brackets(List<string> brr)
{
int count = 0;
List<string> backet = new List<string>(brr);
for (int i = 0; i < backet.Count; i++)
{
if(backet[i] == "(")
{
count = count+1;
}
}
return count;
}
static int[,] wherebracket(List<string> crr , int num) // num为括号(组)的个数
{
int[,] vs = new int[num, 2];
int count = 0;
for (int k = 0; k < crr.Count; k++)
{
if (crr[k] == "(")
{
vs[count, 0] = k+1;
}
else if (crr[k] == ")")
{
vs[count, 1] = k;
}
if(count < num-1)
{
count++;
}
}
return vs;
}
static int calulater(List<string> get , int have)
{
int answer = 0;
int m = 0; // m只用于维持列表循环
int ca = 0; //ca 辅助计算
int a = 0; // a只用于列表循环
int b = 0; // b只用于判断列表结束
int c = 0; // c只用于列表循环
List<string> cal = new List<string>(get);
while (m == 0)
{
if (have == 1)
{
while (a == 0)
{
for (int i = 0; i < cal.Count; i++)
{
if (cal[i] == "*")
{
ca = int.Parse(cal[i - 1]) * int.Parse(cal[i + 1]);
cal[i - 1] = Convert.ToString(ca);
cal.RemoveAt(i);
cal.RemoveAt(i);
}
else if (cal[i] == "/")
{
ca = int.Parse(cal[i - 1]) / int.Parse(cal[i + 1]);
cal[i - 1] = Convert.ToString(ca);
cal.RemoveAt(i);
cal.RemoveAt(i);
}
}
b = priority(cal);
if (b == 0)
{
ca = 0;
break;
}
}
}
if (cal.Count > 2)
{
while (c == 0)
{
if (cal[1] == "+")
{
ca = int.Parse(cal[0]) + int.Parse(cal[2]);
cal[0] = Convert.ToString(ca);
cal.RemoveAt(1);
cal.RemoveAt(1);
}
else if (cal[1] == "-")
{
ca = int.Parse(cal[0]) - int.Parse(cal[2]);
cal[0] = Convert.ToString(ca);
cal.RemoveAt(1);
cal.RemoveAt(1);
}
if (cal.Count == 1)
{
break;
}
}
}
break;
}
return int.Parse(cal[0]);
}
static int calbr(List<string> get ,int have, int brackets)
{
int[,] calul = new int[brackets, 2];
calul = wherebracket(get, brackets);
List<string> brlist = new List<string>();
int count = 0; //循环的次数
int cl = 0;
for (int i = 0; i < brackets; i++)
{
for (int j = calul[count, 0]; j < calul[count, 1];j++)
{
brlist.Add(get[j]);
}
cl = calulater(brlist, have);
get[calul[count, 0]] = Convert.ToString(cl);
get.RemoveRange(calul[count, 0] + 1, calul[count, 1] - calul[count, 0]);
get.RemoveAt(calul[count, 0]-1);
cl = 0;
brlist.Clear();
count++;
}
cl = calulater(get, have);
return cl;
}
}
}
这就是计算器的全部内容了,不过比较简单粗暴,适合编程新手使用和理解,如果有更好的方法的话可以在评论区中点评,谢谢!