In this answer I recommended using
s.replaceFirst("\\.0*$|(\\.\\d*?)0+$", "$1");
but two people complained that the result contained the string "null", e.g., 23.null
. This could be explained by $1
(i.e., group(1)
) being null
, which could be transformed via String.valueOf
to the string "null". However, I always get the empty string. My testcase covers it and
assertEquals("23", removeTrailingZeros("23.00"));
passes. Is the exact behavior undefined?
Best Answer
The documentation of Matcher class from the reference implementation doesn't specify the behavior of
appendReplacement
method when a capturing group which doesn't capture anything (null
) is specified in the replacement string. While the behavior ofgroup
method is clear, nothing is mentioned inappendReplacement
method.Below are 3 exhibits of difference in implementation for the case above:
null
for the case above.Some code has been omitted for the sake of brevity, and is indicated by
...
.1) Sun/Oracle JDK, OpenJDK (Reference implementation)
For the reference implementation (Sun/Oracle JDK and OpenJDK), the code for
appendReplacement
doesn't seem to have changed from Java 6, and it will not append anything when a capturing group doesn't capture anything:Reference
2) GNU Classpath
GNU Classpath, which is a complete reimplementation of Java Class Library has a different implementation for
appendReplacement
in the case above. In Classpath, the classes injava.util.regex
package in Classpath is just a wrapper for classes ingnu.java.util.regex
.Matcher.appendReplacement
callsRE.getReplacement
to process replacement for the matched portion:RE.getReplacement
callsREMatch.substituteInto
to get the content of the capturing group and appends its result directly:REMatch.substituteInto
appends the result ofREMatch.toString(int)
directly without checking whether the capturing group has captured anything:And
REMatch.toString(int)
returnsnull
when the capturing group doesn't capture (irrelevant code has been omitted).So in GNU Classpath's case,
null
will be appended to the string when a capturing group which fails to capture anything is specified in the replacement string.3) Android Open Source Project - Java Core Libraries
In Android,
Matcher.appendReplacement
calls private methodappendEvaluated
, which in turn directly appends the result ofgroup(int)
to the replacement string.Since
Matcher.group(int)
returnsnull
for capturing group which fails to capture,Matcher.appendReplacement
appendsnull
when the capturing group is referred to in the replacement string.It is most likely that the 2 people complaining to you are running their code on Android.