1
2 package com.pnpconsult.zeiterfassung.util;
3
4 import java.text.NumberFormat;
5 import java.text.ParseException;
6 import java.util.Locale;
7
8 /***
9 * Parses simple mathematical expressions from {@link String}s into <tt>double</tt>s.
10 *
11 * <p>
12 *
13 * Following expressions are valid:
14 *
15 * <pre>
16 * ["-"]<em>param1</em>[ "+"|"-"|"*"|"/" ["-"]<em>param2</em>["%"]]
17 * </pre>
18 *
19 *
20 * <p>
21 *
22 * Where <em>param1</em> and <em>param2</em> are numbers of the usual
23 * pattern: #.##0,00 ({@link Locale}dependent). They are parsed using
24 * {@link java.text.DecimalFormat}.
25 *
26 * @author <a href="mailto:powerpete@users.sf.net">M. Petersen</a>
27 * @version $Id: SimpleExpressionParser.java,v 1.3 2004/05/23 16:59:41 powerpete Exp $
28 */
29 public class SimpleExpressionParser
30 {
31 private static final NumberFormat DECIMAL_FORMAT = NumberFormat.getInstance();
32 private static final DualOperator[] OPERATORS =
33 new DualOperator[] {
34 new Multiplication(),
35 new Division(),
36 new Addition(),
37 new Subtraction()};
38
39 private SimpleExpressionParser()
40 {
41 }
42
43 /***
44 * Parses the given expression and returns the result as <tt>double</tt>.
45 *
46 * @param expression
47 * A valid expression.
48 *
49 * @return The parsed value.
50 *
51 * @throws ParseException
52 * If the expression could not be parsed.
53 */
54 public static double parse(String expression) throws ParseException
55 {
56 expression = expression.trim();
57 boolean isPercent = expression.endsWith("%");
58 int endIndex = expression.length();
59 if (isPercent)
60 {
61 endIndex--;
62 }
63
64 for (int i = 0; i < OPERATORS.length; i++)
65 {
66 DualOperator operator = OPERATORS[i];
67 int index = expression.indexOf(operator.getSymbol(), 1);
68 if (index != -1)
69 {
70 String part1 = expression.substring(0, index);
71 String part2 = expression.substring(index + 1, endIndex);
72
73 double param1 = parse(part1);
74 double param2 = parse(part2);
75
76 if (isPercent)
77 {
78 return operator.computeAsPercent(param1, param2);
79 }
80 else
81 {
82 return operator.compute(param1, param2);
83 }
84 }
85 }
86 return DECIMAL_FORMAT.parse(expression).doubleValue();
87 }
88
89 private static class Subtraction extends AbstractDualOperator
90 {
91 public String getSymbol()
92 {
93 return "-";
94 }
95 public double compute(double param1, double param2)
96 {
97 return param1 - param2;
98 }
99 }
100
101 private static class Addition extends AbstractDualOperator
102 {
103 public String getSymbol()
104 {
105 return "+";
106 }
107 public double compute(double param1, double param2)
108 {
109 return param1 + param2;
110 }
111 }
112
113 private static class Division extends AbstractDualOperator
114 {
115 public String getSymbol()
116 {
117 return "/";
118 }
119 public double compute(double param1, double param2)
120 {
121 return param1 / param2;
122 }
123 }
124
125 private static class Multiplication extends AbstractDualOperator
126 {
127 public String getSymbol()
128 {
129 return "*";
130 }
131
132 public double compute(double param1, double param2)
133 {
134 return param1 * param2;
135 }
136 }
137
138 private static abstract class AbstractDualOperator implements DualOperator
139 {
140 public double computeAsPercent(double param1, double param2)
141 {
142 return compute(param1, param1 * param2 / 100);
143 }
144 }
145
146 private static interface DualOperator
147 {
148 String getSymbol();
149 double compute(double param1, double param2);
150 double computeAsPercent(double param1, double param2);
151 }
152 }