I have the following class PlaceHolderConverter used to parse string like "my {} are beautiful" into strings with filled variables.
For instance new PlaceHolderConverter("\\{\\}").format("my {} are beautiful", "flowers") will return the string "my flowers are beautiful".
package something;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class PlaceHolderConverter
{
public Pattern lookForVar;
public PlaceHolderConverter( String placeHolder )
{
this.lookForVar = Pattern.compile( placeHolder );
}
public String format( String text, String... args )
{
if ( args == null || args.length == 0 )
{
return text;
}
StringBuffer stringBuffer = new StringBuffer();
Matcher matcher = lookForVar.matcher( text );
short varCount = 0;
while ( matcher.find() )
{
matcher.appendReplacement( stringBuffer, args[varCount++] );
}
matcher.appendTail( stringBuffer );
return stringBuffer.toString();
}
}
As you can see in the following tests, I have issue with the special character dollar because it’s a special character for java regex.
I tried to solve that with Pattern.quote() but without results.
package something;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.regex.Pattern;
public class PlaceHolderConverterTest
{
private PlaceHolderConverter placeHolderConverter;
@Before
public void before()
{
placeHolderConverter = new PlaceHolderConverter( "\\{\\}" );
}
@Test // SUCCESS
public void whenStringArgsThenReplace()
{
String result = placeHolderConverter.format( "My {} are beautifull", "flowers" );
Assert.assertEquals( "My flowers are beautifull", result );
}
@Test // FAIL IllegalArgumentException illegal group reference while calling appendReplacement
public void assertEscapeDollar()
{
String result = placeHolderConverter.format( "My {} are beautiful", "flow$ers" );
Assert.assertEquals( "My flow$ers are beautiful", result );
}
@Test // FAIL IllegalArgumentException illegal group reference while calling appendReplacement
public void assertEscapeDollarWithQuote()
{
String result = placeHolderConverter.format( "My {} are beautiful", Pattern.quote("flow$ers") );
Assert.assertEquals( "My flow$ers are beautiful", result );
}
}
I also to tried to manually escape the dollar before using it in regexp, with something like .replaceAll("\\$", "\\\\$") but it seems that replaceAll dislike to have to arg1 included in arg2.
How I can fix that ?
Patch can be provided here https://gist.github.com/3937872
When replacing a fixed string, there is no need to call the regex methods on String because there is a simpler one:
input.replace("$", "\\$");. With this method you won’t have any of the troubles caused by the special meaning of the dollar sign, and it will be (very slightly) faster as a bonus.