View Javadoc

1   // Created on 22.10.2003 by mpetersen
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 }