I'm working on a coding challenge to help with regular expressions, and how to write better comments in my code. The class parses a percentage question, and can return the answer.
If anyone has any feedback on the general organization of my class, variable names, or whether or not my comments can be improved, it would be appreciated. My goal is that anyone reading my code can clearly understand what it does and how it works, keeping the 'maintenance' programmer in mind.
package com.percent.model;
import java.util.Arrays;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Class represents a solver for a percentage question.
* @author steve
*/
public class PercentageQueryPatternSolver {
//? is x% of y
private static final Pattern findIsPattern = Pattern.compile("(\\?) is (\\d+)% of (\\d+)");
//x is ?% of y
private static final Pattern findPercentPattern = Pattern.compile("(\\d+) is (\\?)% of (\\d+)");
//x is y% of ?
private static final Pattern findOfPattern = Pattern.compile("(\\d+) is (\\d+)% of (\\?)");
/*Although the numeric values in the queryString passed to the constructor must be integers, we
*store them as Doubles since the value that we are solving for may not be a whole number, and
*we don't know which of the 3 values we are solving for in the beginning. When the query
*is solved, we will remove any trailing .00 values to clean up the output.
*/
private Double firstIsValue;
private Double secondPercentValue;
private Double thirdOfValue;
//These are the valid forms that we expect the query string to take
private Collection<Pattern> validQueryStringPatterns = Arrays.asList(findIsPattern,
findPercentPattern,
findOfPattern);
/**
*
* @param queryString query to be parsed. must take one of the following forms:
* ? is x% of y (example: ? is 10% of 32)
* x is ?% of y (example: 12 is ?% of 62)
* x is y% of ? (example: 25 is 40% of ?)
*
* 'x' and 'y' must be whole numbers, and both values are required
* '?' represents a value to be solved for, and must be entered as '?'
*
* If the queryString does not take one of the above forms, an IllegalArgumentException is thrown
*/
public PercentageQueryPatternSolver(String queryString){
initialize(queryString);
}
//parses the queryString and populates the firstIsValue/secondPercentValue/thirdOfValue variables
private void initialize(String queryString){
boolean queryStringMatchesAValidQueryPattern = false;
for(Pattern pattern : validQueryStringPatterns){
final Matcher patternMatcher = pattern.matcher(queryString);
if(patternMatcher.matches()){
queryStringMatchesAValidQueryPattern = true;
setQueryParameters(patternMatcher);
}
}
if(!queryStringMatchesAValidQueryPattern) {
throw new IllegalArgumentException(queryString + "does not match a known pattern.");
}
}
//pulls the query parameters from the matcher and sets the respective attributes
private void setQueryParameters(Matcher validatedPatternMatcher){
firstIsValue = getDoubleValueOfGroupFromMatcher(validatedPatternMatcher, 1);
secondPercentValue = getDoubleValueOfGroupFromMatcher(validatedPatternMatcher, 2);
thirdOfValue = getDoubleValueOfGroupFromMatcher(validatedPatternMatcher, 3);
}
//returns the double value of a particular group from the matcher
private Double getDoubleValueOfGroupFromMatcher(Matcher matcher, int groupNumber){
String groupValue = matcher.group(groupNumber);
return "?".equals(groupValue) ? null : Double.valueOf(groupValue);
}
//returns the inputDouble formatted for output purposes (remove trailing decimal if 0)
private String getOutputFormattedDoubleValue(Double inputDouble){
String output = String.valueOf(inputDouble);
if (inputDouble == Math.floor(inputDouble)){
output = String.valueOf(inputDouble.intValue());
}
return output;
}
/**
*
* @return the original queryString (used to construct this pattern) with the
* missing value populated.
*/
public String getSolvedPattern(){
if(firstIsValue == null){
firstIsValue = (thirdOfValue * secondPercentValue) / 100;
}
else if(secondPercentValue == null){
secondPercentValue = (firstIsValue * 100) / thirdOfValue;
}
else if(thirdOfValue == null){
thirdOfValue = (firstIsValue * 100) / secondPercentValue;
}
return getOutputFormattedDoubleValue(firstIsValue) + " is " +
getOutputFormattedDoubleValue(secondPercentValue) + "% of " +
getOutputFormattedDoubleValue(thirdOfValue);
}
}