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数 ...
随机推荐
- Java中Map集合的基本功能
Map基本方法: put方法: remove方法: isEmpty方法: . clear方法: containsKey方法: containsValue方法 size方法: get方法: keySet ...
- vue中的$nextTick的常用思路
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新. $nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextT ...
- 发光LED压降与工作电流总结
一.常用的普通贴片0603LED 红色的压降为1.82-1.88V,电流5-8mA 绿色的压降为1.75-1.82V,电流3-5mA 橙色的压降为1.7-1.8V,电流3-5mA 兰色的压降为3.1- ...
- fastDFS配置文件 fdfs_client.conf
# connect timeout in seconds# default value is 30sconnect_timeout=30 # network timeout in seconds# d ...
- 分布式项目spring 配置文件的约束
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.spr ...
- linux:lrzsz安装
Linux中的lrzsc是linux里可代替ftp上传和下载的程序. yum install lrzsc 没有可用软件包 lrzsc. 这时使用 -y即可安装 centos安装:yum -y inst ...
- C#中的this关键字
C# this关键字的四种用法 - 天碼行空 - 博客园 https://www.cnblogs.com/jh007/p/6120654.html C#中this关键字详解 - lin37985的专栏 ...
- 安装jdk 并放在 /usr/java/default 目录下
安装步骤 . mkdir /usr/java 2. tar -xvf jdk*.tar.gz -C /usr/java/ 记得将* 换成版本即可3. ln -s /usr/java/jdk* /usr ...
- bigger is greater
题目: Lexicographical order is often known as alphabetical order when dealing with strings. A string i ...
- rmq +二分暴力 hdu 5726
参考博客 题意:n 个数字的数列,有m个询问:求出 L 到 R 的 gcd(最大公约数 ),然后问这整个序列中有多少个区间的 gcd 和这个一样. 分析:L 到 R的gcd直接用RM ...