package chatty.util; /** * Replaces parameters in a String. * * @author tduva */ public class ParameterReplacer { private final StringBuilder output = new StringBuilder(); private StringBuilder buffer = new StringBuilder(); private Object[] parameters; private boolean startFound; private boolean required; private boolean escape; private boolean toEnd; private int index1 = -1; private int index2 = -1; private boolean invalidParameters; /** * Replaces parameter tokens found in {@code input} with the parameters in * the {@code parameters} array. If an array element exists, then it is * interpreted and used as a valid parameter, even if it is {@code null} or * it's {@code String} representation is empty. * * <p> * The objects given as parameters are appended using * {@link java.lang.StringBuilder#append(Object)} (which turns the Object * into a {@code String} using {@link String#valueOf(Object)}).</p> * * <ul> * <li>$1 means replace with the first element in the array</li> * <li>$1- means replace with the first to the last element</li> * <li>$$1 requirement parameter, will return {@code null} if the array * doesn't contain this element</li> * <li>\$ to use literal $, \\ to use literal \</li> * </ul> * * @param input The input to replace, cannot be {@code null} * @param parameters The array of {@code Object}s to use a parameters * @return The modified {@code input} {@code String} or {@code null} if a * required parameter wasn't specified */ public String replace(String input, Object[] parameters) { this.parameters = parameters; for (int i=0;i<input.length();i++) { char c = input.charAt(i); if (c == '\\') { if (escape) { escape = false; output.append(c); } else { escape = true; } } else if (!escape && c == '$') { if (required) { output.append(buffer.subSequence(0, 1)); buffer.deleteCharAt(0); } if (startFound) { required = true; } startFound = true; buffer.append(c); } else if (!escape && startFound && isNumber(c)) { int index = Character.getNumericValue(c) - 1; if (index1 == -1) { index1 = index; } else if (toEnd && index > index1) { index2 = index; } else { clear(); output.append(c); } } else if (!escape && startFound && index1 != -1 && c == '-') { toEnd = true; clear(); } else { clear(); output.append(c); } if (invalidParameters) { break; } } clear(); if (invalidParameters) { return null; } return output.toString(); } /** * Checks if a match to replace has been found and appens the appropriate * parameter or the buffer if nothing has been found. */ private void clear() { if (startFound) { if (index1 != -1) { //System.out.println(index1+" "+index2+" "+required); if (index1 < 0 || index1 >= parameters.length) { if (required) { invalidParameters = true; } } else if (toEnd) { output.append(buildRange(parameters, index1, index2)); } else { output.append(parameters[index1]); } buffer = new StringBuilder(); } else { dumpBuffer(); } } reset(); } /** * Appends the current buffer contents to the output and clears the buffer. */ private void dumpBuffer() { output.append(buffer); buffer = new StringBuilder(); } /** * Reset all the fields that describe a match. */ private void reset() { startFound = false; required = false; escape = false; toEnd = false; index1 = -1; index2 = -1; } /** * Checks if the given character is considered a number for replacing * parameters. * * @param c The character * @return {@code true} if a number in the range 1-9, {@code false} * otherwise */ private static boolean isNumber(char c) { return c >= '1' && c <= '9'; } /** * Constructs a String out of an array of Strings that consists of the * array elements with the indices {@code start} to {@code end}. * * <p> * If {@code end} is {@code -1} or {@code end} > length of the array, * then elements from {@code start} to the end of the array are used.</p> * * @param input The array of Strings * @param start The start index * @param end The end index * @return The constructed {@code String} or {@code null} if {@code start} * < 0 or {@code start} > length of the array */ private static String buildRange(Object[] input, int start, int end) { if (start < 0 || start > input.length - 1) { return null; } if (end == -1) { end = input.length; } StringBuilder output = new StringBuilder(); for (int i=start;i<=end;i++) { if (i >= input.length) { break; } if (i != start) { output.append(" "); } output.append(input[i]); } return output.toString(); } public static final void main(String[] args) { String text = "/me slaps $$1 around a bit with a large trout"; String parameter = "test"; String[] parameters = parameter.split(" "); //parameters[0] = null; //String[] parameters = new String[0]; ParameterReplacer replacer = new ParameterReplacer(); //System.out.println(replacer.replace(text, parameters)); } }