C#利用栈实现字符串运算解析
附上参考文章链接:https://blog.csdn.net/qq_34831781/article/details/80104219
本人整合修复一些bug后的代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text; // 解析计算字符串公式
namespace CalcuStrFormula
{
// 处理类
class Handler
{
private Stack _complexNumberStack = new Stack();
private Stack _operatorStack = new Stack();
private Parser _parser = new Parser();
private Operators _operators = new Operators(); private static Handler _instance;
public static Handler instance
{
get
{
if (_instance == null)
{
_instance = new Handler();
}
return _instance;
}
} public ComplexNumber Process(string inputString)
{
_complexNumberStack.Clear();
_operatorStack.Clear(); Queue<object> queue = _parser.Parse(inputString);
ComplexNumber complexNumber = null;
char op, topOp;
int count = queue.Count;
for (int i = ; i < count; i++)
{
object obj = queue.Dequeue();
if (obj is char)
{
op = (char)obj;
if (_operatorStack.Count == )
{
_operatorStack.Push(op);
}
else
{
topOp = (char)_operatorStack.Peek();
if (op == '(')
{
_operatorStack.Push(op); // 左括号直接压入。不判断栈顶
}
else if (op == ')')
{
// 右括号压入前观察栈顶,若栈顶是左括号,则弹出栈顶的左括号
// 否则弹出栈顶运算符,从数栈中弹出操作数进行运算,并将结果重新压入数栈,直到遇到左括号
while ((topOp = (char)_operatorStack.Pop()) != '(')
{
ComplexNumber c1 = (ComplexNumber)_complexNumberStack.Pop(); // 符号右边数
ComplexNumber c2 = null; // 符号左边数
if (_operators.IsTwoNumOperator(topOp))
{
c2 = (ComplexNumber)_complexNumberStack.Pop();
}
ComplexNumber c3 = _operators.Compute(topOp, c2, c1);
_complexNumberStack.Push(c3);
}
}
else if (_operators.ComparePriority(topOp, op) <= )
{
// 若即将压入的运算符不是括号,则比较栈顶运算符和即将压入的运算符的优先级
// 如果栈顶优先级高,则将栈顶运算符取出运算,直到栈顶优先级不大于其。
while (_operatorStack.Count != && _operators.ComparePriority((char)_operatorStack.Peek(), op) <= )
{
topOp = (char)_operatorStack.Pop();
ComplexNumber c1 = (ComplexNumber)_complexNumberStack.Pop(); // 符号右边数
ComplexNumber c2 = null; // 符号左边数
if (_operators.IsTwoNumOperator(topOp))
{
c2 = (ComplexNumber)_complexNumberStack.Pop();
}
ComplexNumber c3 = _operators.Compute(topOp, c2, c1);
_complexNumberStack.Push(c3);
}
_operatorStack.Push(op);
}
else
{
_operatorStack.Push(op);
}
}
}
else if (obj is ComplexNumber)
{
complexNumber = (ComplexNumber)obj;
_complexNumberStack.Push(complexNumber);
} if (queue.Count == )
{
while (_operatorStack.Count != )
{
topOp = (char)_operatorStack.Pop();
ComplexNumber c1 = (ComplexNumber)_complexNumberStack.Pop(); // 符号右边数
ComplexNumber c2 = null; // 符号左边数
if (_operators.IsTwoNumOperator(topOp))
{
c2 = (ComplexNumber)_complexNumberStack.Pop();
}
ComplexNumber c3 = _operators.Compute(topOp, c2, c1);
_complexNumberStack.Push(c3);
}
}
} return (ComplexNumber)_complexNumberStack.Pop();
}
} // 3+4i解析成Queue包含 3, +, 4i
public class Parser
{
private Operators _operators = new Operators(); public Queue<object> Parse(string input)
{
input = input.Replace(" ", "");
if (input.StartsWith("-")) input = '' + input; char[] arr = input.ToCharArray();
Queue<char> queueChar = new Queue<char>();
foreach (char x in arr)
{
queueChar.Enqueue(x);
}
Queue<object> queueResult = ParseStringQueue(queueChar);
return queueResult;
} // 传入字符串队列,返回封装好的队列。
// ComplexNumber对象或char类型运算符各占用一个结点
private Queue<object> ParseStringQueue(Queue<char> queue)
{
Queue<object> secondQ = new Queue<object>();
char c;
StringBuilder sb = null;
string temp;
int count = queue.Count;
bool flag = false; // false表示允许创建新SB对象进行缓存数字字符串
for (int i = ; i < count; i++)
{
c = queue.Dequeue();
if (!_operators.Contains(c))
{
// 如果扫描到的不是运算符,则将其加入到buffer尾部
if (!flag)
{
flag = true;
sb = new StringBuilder();
}
sb.Append(c);
}
if (_operators.Contains(c) || queue.Count == )
{
// 如果扫描到的是运算符,则将缓冲区中的串加入队尾
if (sb != null && flag == true)
{
temp = sb.ToString();
try
{
if (temp.EndsWith("i"))
{
if (temp.Length == )
{
secondQ.Enqueue(new ComplexNumber(, ));
}
else
{
// i前有数字则开出数字部分。
temp = temp.Substring(, temp.Length - );
secondQ.Enqueue(new ComplexNumber(, double.Parse(temp)));
}
}
else
{
secondQ.Enqueue(new ComplexNumber(double.Parse(temp), ));
}
sb = null;
flag = false;
}
catch (Exception e)
{
UnityEngine.Debug.Log("Error " + e.ToString());
}
}
// 如果是运算符,则最后将运算符放入队。
if (_operators.Contains(c))
{
secondQ.Enqueue(c);
}
}
} return secondQ;
}
} // 复数类,提供实数域虚数域,getset方法,加减乘除以及toString()方法
class ComplexNumber
{
private double _realPart; // 实数部分
private double _imaginPart; // 虚数部分 public ComplexNumber()
{
_realPart = 0.0;
_imaginPart = 0.0;
}
public ComplexNumber(double r, double i)
{
_realPart = r;
_imaginPart = i;
}
public ComplexNumber(ComplexNumber c)
{
_realPart = c.GetRealPart();
_imaginPart = c.GetImaginaryPart();
} // get,set方法
public double GetRealPart()
{
return _realPart;
}
public double GetImaginaryPart()
{
return _imaginPart;
}
public void SetRealPart(double d)
{
_realPart = d;
}
public void SetImaginaryPart(double d)
{
_imaginPart = d;
} // 加
public ComplexNumber ComplexAdd(ComplexNumber c)
{
return new ComplexNumber(_realPart + c.GetRealPart(), _imaginPart + c.GetImaginaryPart());
}
public ComplexNumber ComplexAdd(double c)
{
return new ComplexNumber(_realPart + c, _imaginPart);
}
// 减
public ComplexNumber ComplexMinus(ComplexNumber c)
{
return new ComplexNumber(_realPart - c.GetRealPart(), _imaginPart - c.GetImaginaryPart());
}
public ComplexNumber ComplexMinus(double c)
{
return new ComplexNumber(_realPart - c, _imaginPart);
}
// 乘
public ComplexNumber ComplexMulti(ComplexNumber c)
{
return new ComplexNumber(
_realPart * c.GetRealPart()
- _imaginPart * c.GetImaginaryPart(),
_realPart *
c.GetImaginaryPart()
+ _imaginPart *
c.GetRealPart());
}
public ComplexNumber ComplexMulti(double c)
{
return new ComplexNumber(_realPart * c, _imaginPart * c);
}
// 除
public ComplexNumber ComplexDivision(ComplexNumber c)
{
return new ComplexNumber((_realPart * c.GetRealPart() + _imaginPart * c.GetImaginaryPart())
/ (c.GetRealPart() * c.GetRealPart() + c.GetImaginaryPart() * c.GetImaginaryPart())
, (_imaginPart * c.GetRealPart() - _realPart * c.GetImaginaryPart())
/ (c.GetRealPart() * c.GetRealPart() + c.GetImaginaryPart() * c.GetImaginaryPart()));
}
public ComplexNumber ComplexDivision(double c)
{
return new ComplexNumber(_realPart / c, _imaginPart / c);
}
// 幂
public ComplexNumber ComplexPow(ComplexNumber c)
{
int pow;
if (int.TryParse(c.GetRealPart().ToString(), out pow))
{
ComplexNumber origin = new ComplexNumber(this);
ComplexNumber multi = new ComplexNumber(this);
for (int i = ; i < pow - ; i++)
{
origin = origin.ComplexMulti(multi);
}
return origin;
}
else
{
return ComplexPow(c.GetRealPart());
}
}
public ComplexNumber ComplexPow(double c)
{
return new ComplexNumber(Math.Pow(_realPart, c), 0.0);
}
// 最小值
public ComplexNumber ComplexMinimum(ComplexNumber c)
{
if (_realPart <= c.GetRealPart()) return this;
return c;
}
// 最大值
public ComplexNumber ComplexMaximum(ComplexNumber c)
{
if (_realPart >= c.GetRealPart()) return this;
return c;
}
// 转int
public ComplexNumber ToFloorInt()
{
_realPart = Math.Floor(_realPart);
return this;
} public override string ToString()
{
return "(" + _realPart + " + " + _imaginPart + " i" + ")";
}
} // 操作符类
class Operators
{
private char[][] _signOperator; public Operators()
{
// 从上到下,优先级由高到低
_signOperator = new char[][];
_signOperator[] = new char[];
_signOperator[][] = '^';
_signOperator[][] = 's'; // 最小值
_signOperator[][] = 'b'; // 最大值
_signOperator[][] = 'i'; // int值
_signOperator[] = new char[];
_signOperator[][] = '*';
_signOperator[][] = '/';
_signOperator[] = new char[];
_signOperator[][] = '+';
_signOperator[][] = '-';
_signOperator[] = new char[];
_signOperator[][] = '(';
_signOperator[][] = ')';
} // 比较操作符优先级
public int ComparePriority(char firstSign, char secondSign)
{
int priorityF = , priorityS = ;
for (int i = ; i < _signOperator.Length; i++)
{
foreach (char x in _signOperator[i])
{
if (firstSign == x)
{
priorityF = i;
}
if (secondSign == x)
{
priorityS = i;
}
}
} return (priorityF - priorityS);
} // 是否是需要两个参数的操作符
public bool IsTwoNumOperator(char op)
{
if (op == 'i') return false;
return true;
} public bool Contains(char x)
{
if (x == '(' || x == ')')
{
UnityEngine.Debug.LogError(x + "为中文字符,请改为英文字符");
} foreach (char[] arr in _signOperator)
{
foreach (char y in arr)
{
if (x == y)
{
return true;
}
}
}
return false;
} public ComplexNumber Compute(char op, ComplexNumber c1, ComplexNumber c2)
{
ComplexNumber result = null;
switch (op)
{
case '+': result = c1.ComplexAdd(c2); break;
case '-': result = c1.ComplexMinus(c2); break;
case '*': result = c1.ComplexMulti(c2); break;
case '/': result = c1.ComplexDivision(c2); break;
case '^': result = c1.ComplexPow(c2); break;
case 's': result = c1.ComplexMinimum(c2); break;
case 'b': result = c1.ComplexMaximum(c2); break;
case 'i': result = c2.ToFloorInt(); break;
}
return result;
}
}
}
仓促上传待整理。。。
C#利用栈实现字符串运算解析的更多相关文章
- 利用栈实现字符串中三种括号的匹配问题c++语言实现
编写一个算法,检查一个程序中的花括号,方括号和圆括号是否配对,若能够全部配对则返回1,否则返回0. Head.h: #ifndef HEAD_H_INCLUDED #define HEAD_H_INC ...
- C++ 利用栈解决运算问题
2017-06-27 19:19:18 第一步需要将中缀表达式转为后缀表达式.这步的转化可以说是本题的核心. 主要的转化手段是利用栈,有如下几个规则: 数字直接输出 "("直接进栈 ...
- buuoj [RoarCTF 2019]Easy Calc(利用PHP的字符串解析特性)
web [RoarCTF 2019]Easy Calc(利用PHP的字符串解析特性) 先上源码 <?phperror_reporting(0);if(!isset($_GET['num'])){ ...
- python 利用栈实现复杂计算器
#第五周的作业--多功能计算器#1.实现加减乘除及括号的优先级的解析,不能使用eval功能,print(eval(equation))#2.解析复杂的计算,与真实的计算器结果一致#用户输入 1 - 2 ...
- 三道题(关于虚表指针位置/合成64位ID/利用栈实现四则运算)
第一题 C++标准中,虚表指针在类的内存结构位置没有规定,不同编译器的实现可能是不一样的.请实现一段代码,判断当前编译器把虚表指针放在类的内存结构的最前面还是最后面. 第二题 在游戏中所有物品的实例 ...
- 利用栈实现算术表达式求值(Java语言描述)
利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...
- [Java]利用栈判断括号是否完整配对
利用栈实现判断字符串中的括号是否都是配对的. 主要算法是依次读取字符串中的每一个字符,如果是左括号则将左括号压入栈中,如果是右括号则从栈中弹出最上面的字符,若两者不是同种括号或栈内已经没有字符就返回f ...
- Java开发笔记(三十八)利用正则表达式校验字符串
前面多次提到了正则串.正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了 ...
- Kotlin入门(31)JSON字符串的解析
json是App进行网络通信最常见的数据交互格式,Android也自带了json格式的处理工具包org.json,该工具包主要提供了JSONObject(json对象)与JSONArray(json数 ...
随机推荐
- Python 十大装 B 语法解析
Python 是一种代表简单思想的语言,其语法相对简单,很容易上手.不过,如果就此小视 Python 语法的精妙和深邃,那就大错特错了.本文精心筛选了最能展现 Python 语法之精妙的十个知识点,并 ...
- C# 16进制转字符串,字符串转16进制
{ //========================================================== //16进制转字符串 public static byte[] HexTo ...
- Vue学习笔记【23】——Vue组件(组件的定义)
定义Vue组件 什么是组件: 组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件即可: 组件化和模块化的不同: ...
- 【LeetCode 25】K 个一组翻转链表
题目链接 [题解] 模拟就好. 就k个k个节点地翻转. 每个节点都把next域指向它前面那个节点 修改完之后把这个节点前面的那个节点的next域改成这一段的最后一个节点. 然后把这一段最左边的那个节点 ...
- Minimum Snap轨迹规划详解(3)闭式求解
如果QP问题只有等式约束没有不等式约束,那么是可以闭式求解(close form)的.闭式求解效率要快很多,而且只需要用到矩阵运算,不需要QPsolver. 这里介绍Nicholas Roy文章中闭式 ...
- contest-20191021
文化课读的真不开心 回来竞赛 假人 sol 根据不等式有 abs(a-b)+abs(b-c)>=abs(a-c) 那么每一个都会选. 可以发现每一段只会选在端点上(否则移到端点更优). 那么dp ...
- Zend Studio出现 Some characters cannot be mapped using "GBK" character encoding 错误
解决办法: Window->Profermance->General->Content Types->Text看目录下面的每个文件,包括子目录里面 Default encodi ...
- tomcat 相关异常
端口没有被占用却提示Several ports (8005, 8080, 8009) required by Tomcat??? 解决办法:1.运行cmd进入命令行界面:2.运行命令: netsh w ...
- mysql的数据类型int、bigint、smallint 和 tinyint及id 类型变换
bigint 从 -2^63 (-9223372036854775808) 到 2^63-1 (9223372036854775807) 的整型数据(所有数字).存储大小为 8 个字节. int 从 ...
- Hibernate 和 JPA 注解
转载请注明:Hibernate 和 JPA 注解 | 言曌博客 1.@Entity(name="EntityName") 必须, name为可选,对应数据库中一的个表 2.@Tab ...