StrSubstitutor can preserve escapes

StrSubstitutor can now optionally preserve the escape character for an
escaped reference, which is useful when substitution takes place in
multiple phases and some references are intentionally unresolved.  Prior
to this change, an unresolved reference `${a}` and an escaped reference
`$${a}` may result in the same string `${a}`, making it impossible for
an additional substitution phase to distinguish between escaped
references and non-escaped references.
This commit is contained in:
Samuel Karp 2016-02-03 15:45:21 -08:00
parent a72a5ced53
commit e55aaa5706
2 changed files with 48 additions and 0 deletions

View File

@ -165,6 +165,10 @@ public class StrSubstitutor {
* The flag whether substitution in variable names is enabled. * The flag whether substitution in variable names is enabled.
*/ */
private boolean enableSubstitutionInVariables; private boolean enableSubstitutionInVariables;
/**
* Whether escapes should be preserved. Default is false;
*/
private boolean preserveEscapes = false;
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
/** /**
@ -768,6 +772,10 @@ public class StrSubstitutor {
// found variable start marker // found variable start marker
if (pos > offset && chars[pos - 1] == escape) { if (pos > offset && chars[pos - 1] == escape) {
// escaped // escaped
if (preserveEscapes) {
pos++;
continue;
}
buf.deleteCharAt(pos - 1); buf.deleteCharAt(pos - 1);
chars = buf.buffer; // in case buffer was altered chars = buf.buffer; // in case buffer was altered
lengthChange--; lengthChange--;
@ -1192,4 +1200,29 @@ public class StrSubstitutor {
final boolean enableSubstitutionInVariables) { final boolean enableSubstitutionInVariables) {
this.enableSubstitutionInVariables = enableSubstitutionInVariables; this.enableSubstitutionInVariables = enableSubstitutionInVariables;
} }
/**
* Returns the flag controlling whether escapes are preserved during
* substitution.
*
* @return the preserve escape flag
*/
public boolean isPreserveEscapes() {
return preserveEscapes;
}
/**
* Sets a flag controlling whether escapes are preserved during
* substitution. If set to <b>true</b>, the escape character is retained
* during substitution (e.g. <code>$${this-is-escaped}</code> remains
* <code>$${this-is-escaped}</code>). If set to <b>false</b>, the escape
* character is removed during substitution (e.g.
* <code>$${this-is-escaped}</code> becomes
* <code>${this-is-escaped}</code>). The default value is <b>false</b>
*
* @param preserveEscapes
*/
public void setPreserveEscapes(final boolean preserveEscapes) {
this.preserveEscapes = preserveEscapes;
}
} }

View File

@ -623,6 +623,21 @@ public class StrSubstitutorTest {
assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@")); assertEquals("Hello there commons!", StrSubstitutor.replace("@greeting@ there @name@!", map, "@", "@"));
} }
@Test
public void testSubstitutePreserveEscape() {
final String org = "${not-escaped} $${escaped}";
final Map<String, String> map = new HashMap<String, String>();
map.put("not-escaped", "value");
StrSubstitutor sub = new StrSubstitutor(map, "${", "}", '$');
assertFalse(sub.isPreserveEscapes());
assertEquals("value ${escaped}", sub.replace(org));
sub.setPreserveEscapes(true);
assertTrue(sub.isPreserveEscapes());
assertEquals("value $${escaped}", sub.replace(org));
}
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) { private void doTestReplace(final String expectedResult, final String replaceTemplate, final boolean substring) {
final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1); final String expectedShortResult = expectedResult.substring(1, expectedResult.length() - 1);