C#化学公式解析
给定一个用字符串展示的化学公式,计算每种元素的个数(求C#答案)。
规则如下:
元素命名采用驼峰命名,例如 Mg
() 代表内部的基团,代表阴离子团
[] 代表模内部链节通过化学键的连接,并聚合
例如:H2O => H2O1 Mg(OH)2 => H2Mg1O2
输入:
- 化学公式的字符串表达式,例如:K4[ON(SO3)2]2 。
输出: - 元素名称及个数:K4N2O14S4,并且按照元素名称升序排列。
示例:
输入:K4[ON(SO3)2]2
输出:K4N2O14S4
回答
//左到右遇到元素 数量 左括号 入栈
//遇到右括号 获取(基团/聚合)数量 出栈增加括号内元素的数量 然后再入栈
public static string Parse(string expression)
{
var stack = new Stack<string>();
var index = 0;
while (index < expression.Length)
{
if (char.IsLetter(expression[index]))
{
var e = GetNextElement(expression, index);
stack.Push(e);
index += e.Length;
if (index < expression.Length && char.IsNumber(expression[index]))
{
var n = GetNextNumber(expression, index);
stack.Push(n);
index += n.Length;
}
else
{
stack.Push("1");
}
}
else if (expression[index] == '[' || expression[index] == '(')
{
stack.Push(expression[index].ToString());
index++;
}
else
{
var c = 1;
if (index + 1 < expression.Length && char.IsNumber(expression[index + 1]))
{
var n = GetNextNumber(expression, index + 1);
index += n.Length + 1;
c = int.Parse(n);
}
else
{
index++;
}
var st = new Stack<string>();
while (stack.Peek() != "[" && stack.Peek() != "(")
{
var e = stack.Pop();
if (int.TryParse(e, out var t))
{
st.Push((t * c).ToString());
}
else
{
st.Push(e);
}
}
stack.Pop();
while (st.Count > 0)
{
stack.Push(st.Pop());
}
}
}
var dic = new Dictionary<string, int>();
while (stack.Count > 0)
{
var c = int.Parse(stack.Pop());
var e = stack.Pop();
if (dic.TryGetValue(e, out var t))
{
dic[e] = t + c;
}
else
{
dic[e] = c;
}
}
var es = dic.Keys.OrderBy(k => k);
var re = new StringBuilder();
foreach (var e in es)
{
re.Append($"{e}{dic[e]}");
}
return re.ToString();
}
public static string GetNextElement(string txt, int startIndex)
{
var len = 1;
while (startIndex + len < txt.Length && char.IsLower(txt[startIndex + len]))
{
len++;
}
return txt.Substring(startIndex, len);
}
public static string GetNextNumber(string txt, int startIndex)
{
var len = 1;
while (startIndex + len < txt.Length && char.IsNumber(txt[startIndex + len]))
{
len++;
}
return txt.Substring(startIndex, len);
}
