Repository navigation
Keep StrSubstitutor from treating a value's trailing $ as an escape - #1834
Conversation
After a variable is replaced, substituteRecursive resumes scanning at
the end of the inserted value, and the escape check looks at the char
before the next prefix bounded only by the scan offset. A value ending
in the escape char therefore escaped the variable that follows it in
the template: the value lost its last char and the next variable was
left unresolved, e.g. price=5$ makes "${price}${x}" return "5${x}"
instead of "5$X".
Only accept an escape char at or after the end of the last
substitution.
(#1834) Tests and Javadoc
|
Yes, Commons Text has the same issue. Repro against 1.15.0: Map<String, String> m = Map.of("price", "5$", "x", "X", "a", "$", "b", "B");
StringSubstitutor s = new StringSubstitutor(m);
s.replace("${price}${x}"); // expected "5$X", actual "5${x}"
s.replace("${a}${b}"); // expected "$B", actual "${b}"Same fix should carry over: only accept an escape at or after the end of the last substitution. I can open a Commons Text PR for it with your new tests ported over, if that works for you. Thanks for merging, and for the extra tests. |
|
@alhudz Thank you, feel free to create a PR for Commons Text. |
|
Hello @alhudz Would you please provide a PR for Commons Text? |
|
Opened apache/commons-text#786 with the same fix in |
StrSubstitutortakes the escape character from the end of a substituted value when another variable follows it directly in the template:After
${price}is replaced,substituteRecursiveresumes scanning at the end of the inserted value, and the escape check (pos > offset && chars[pos - 1] == escape) reaches back into that value. The value loses its trailing$and${x}is passed through unresolved, so whoever supplies a value can stop the next template variable from being substituted. The class Javadoc places the escape in the template, in front of a variable reference.The fix only accepts an escape character at or after the end of the last substitution. Escapes written in the template, escapes inside a value,
preserveEscapesand nested/recursive substitution behave as before. The newtestReplaceValueEndingWithEscapefails without the change (expected: <The price is 5$lazy dog.> but was: <The price is 5${target}.>) and passes with it.Commons Text 1.15.0
StringSubstitutorbehaves the same way ("5${x}"for the input above), so the same change applies there.mvn; that'smvnon the command line by itself.