I looked around a bit for a solution to parsing out a chemical formula that contained molecular components that may have their own suffixes for the purposes of being able to parse a formula for its complete atomic fraction.
How would one do this in Java?
Not having been able to find a way to do this in short order (and not having done a fun algorithm in a while) I settled on a stack implementation, as it's actually less complicated than a math operation stack.
Going backward through the stack, you only have to be aware of a few things, as this is fundamentally a modified implementation of a common solution to parsing a mathematical statement.
1) Your integer suffix can be built of multiple characters
2) Your integer suffix could be a multiplier (next character being a ")")
3) You need to handle for implicit "1"s
The implementation pops characters off one stack and pushes only letters and numbers onto your "return stack".
String expandFormula(String s){
Stack<Character> stack = new Stack();
Stack<Character> hanoi = new Stack();
char[] ca = s.toCharArray();
Character c;
List<Integer> multipliers = new ArrayList();
String multiBuff;
int val;
boolean flag;
for (int i = 0; i < ca.length; i++)
stack.push(ca[i]);
while(!stack.isEmpty()){
c = stack.pop();
if (Character.isLetter(c)){
try{
//previous parse was end of Symbol, implicit "1"
flag = Character.isUpperCase(hanoi.peek());
}
catch(EmptyStackException ese){ //change exception
flag = false;
}
//push implicit 1
if (flag){
stack.push(c);
stack.push('1');
}
//continue as usual
else
hanoi.push(c);
}
//begin number parsing
else if(Character.isDigit(c)){
flag = false;
multiBuff = c +"";
//parse the integer out
while(Character.isDigit(stack.peek())){
c = stack.pop();
multiBuff = c + multiBuff;
}
//if next char is ), then value is a suffix
if (stack.peek() == ')'){
flag = true;
stack.pop();
multipliers.add(Integer.parseInt(multiBuff));
//pop successive )s
while(stack.peek() == ')'){
stack.pop();
multipliers.add(1);
}
}
if(Character.isLetter(stack.peek())){
val = flag ? 0 : Integer.parseInt(multiBuff);
//get full value of
for(Integer i : multipliers){
if (val == 0)
val = i;
else
val *= i;
}
//trim and push first decibit
while(val > 0){
hanoi.push(Character.forDigit(val % 10, 10));
val /= 10;
}
}
}
//end of nest, remove most recent multiplier
else if(c == '(')
try{
multipliers.remove(multipliers.size()-1);
}
catch(ArrayIndexOutOfBoundsException aioobe){
}
}
multiBuff = "";
while(!hanoi.isEmpty())
multiBuff += hanoi.pop();
return multibuff;
}
This solution can be converted directly to your output string by:
1) Change "hanoi" to string
2) Change "hanoi.push(c)" to hanoi = c + hanoi
3) Change "hanoi.peek()" to "hanoi.charAt(0)"
4) Change Exceptions as necessary (or use general exceptions anyway)
5) Just return hanoi instead of the multibuff thing at the bottom.