I'm trying to build simple pattern matching in a string.
ie., Given a template
of: "Hello ${1}"
and an input
of "Hello world"
, I'd like to be able to return a map of 1='world'
.
This test demonstrates what I'm trying to acheive:
@Test
public void detectsTokenValues()
{
Properties properties = formatter.getTokenValues("${1}/andThen/${2}/followedBy/${3}","start/andThen/middle/followedBy/end");
assertThat((String) properties.get("1"), equalTo("start"));
assertThat((String) properties.get("2"), equalTo("middle"));
assertThat((String) properties.get("3"), equalTo("end"));
}
Here's my implementation. It works, but I feel like it's convoluted, and I suspect there's Regex or other JDK native features I could be using to make it simpler.
// Matches ${0} - ${9999} etc., But not ${variblesWithWords}
private static final Pattern NUMERIC_VARIABLES = Pattern.compile("\\$\\{([0-9]+?)\\}");
Properties getTokenValues(String template, String input) {
Properties properties = new Properties();
Matcher matcher = NUMERIC_VARIABLES.matcher(sourcestring);
final int variableWrapperLength = "${}".length();
int accumulativeOffset = 0;
while (matcher.find())
{
String variableName = matcher.group(1);
String value = null;
if (matcher.end() >= template.length())
{
value = input.substring(matcher.start() + accumulativeOffset);
} else {
// Find the character after the variable in the template.
// This serves as the end-delimeter in the input string.
String endDelimiter = template.substring(matcher.end(),matcher.end()+1);
int variableEndIndex = findEndDelimiterIndex(input, matcher.start() + 1,
endDelimiter);
value = input.substring(matcher.start() + accumulativeOffset, variableEndIndex);
// Adjust the accumulative offset to account for the difference
// in lengths between the variableName (eg., ${1})
// and the the actual value (eg., 'foo')
accumulativeOffset += value.length() - (variableWrapperLength + variableName.length());
}
if (value != null)
properties.put(variableName, value);
}
return properties;
}
private int findEndDelimiterIndex(String input, int fromIndex,
String endDelimiter) {
// Find the first instance of the delimiter in the input string
// that occurs after the start of our matches variable.
if (fromIndex > input.length())
{
return Integer.MAX_VALUE;
}
int variableEndIndex = input.indexOf(endDelimiter,fromIndex);
return variableEndIndex;
}
How can I improve this method?
findEndDelimiterIndex
andgetMatcher
too? – palacsint Aug 31 '12 at 4:08getMatcher
is replaced withNUMERIC_VARIABLES.matcher(sourcestring);
-- updated in example. – Marty Pitt Aug 31 '12 at 5:39NUMERIC_VARIABLES.matcher(sourcestring);
shouldn't beNUMERIC_VARIABLES.matcher(template)
? – palacsint Aug 31 '12 at 19:56