Copilot commented on code in PR #2688:
URL: https://github.com/apache/groovy/pull/2688#discussion_r3562836208


##########
src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java:
##########
@@ -3466,6 +3469,103 @@ public static BigInteger toBigInteger(final 
CharSequence self) {
         return new BigInteger(self.toString().trim());
     }
 
+    /**
+     * Parses a CharSequence into a Number using the given locale, honouring
+     * locale-specific grouping and decimal symbols. Unlike {@link 
#toBigDecimal(CharSequence)},
+     * parsing is lenient (a leading numeric prefix is accepted) and 
grouping-aware.
+     * <pre class="groovyTestCase">
+     * assert '1.234,5'.toNumber(Locale.GERMANY) == 1234.5
+     * </pre>
+     *
+     * @param self   a CharSequence
+     * @param locale the locale defining the number symbols
+     * @return the parsed Number
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toNumber(final CharSequence self, final Locale 
locale) {
+        try {
+            return 
NumberFormat.getNumberInstance(locale).parse(self.toString());
+        } catch (ParseException e) {
+            throw new NumberFormatException("Unparseable number: \"" + self + 
"\"");
+        }

Review Comment:
   The new parsing methods wrap ParseException in NumberFormatException but 
drop the original cause, making failures harder to diagnose (stack traces lose 
the underlying ParseException details). Consider chaining the cause via 
initCause while keeping the public exception type the same.



##########
src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java:
##########
@@ -3466,6 +3469,103 @@ public static BigInteger toBigInteger(final 
CharSequence self) {
         return new BigInteger(self.toString().trim());
     }
 
+    /**
+     * Parses a CharSequence into a Number using the given locale, honouring
+     * locale-specific grouping and decimal symbols. Unlike {@link 
#toBigDecimal(CharSequence)},
+     * parsing is lenient (a leading numeric prefix is accepted) and 
grouping-aware.
+     * <pre class="groovyTestCase">
+     * assert '1.234,5'.toNumber(Locale.GERMANY) == 1234.5
+     * </pre>
+     *
+     * @param self   a CharSequence
+     * @param locale the locale defining the number symbols
+     * @return the parsed Number
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toNumber(final CharSequence self, final Locale 
locale) {
+        try {
+            return 
NumberFormat.getNumberInstance(locale).parse(self.toString());
+        } catch (ParseException e) {
+            throw new NumberFormatException("Unparseable number: \"" + self + 
"\"");
+        }
+    }
+
+    /**
+     * Parses a CharSequence into a Number using the currency format of the 
default locale.
+     * The result is an exact {@link BigDecimal}.
+     *
+     * @param self a CharSequence
+     * @return the parsed Number (a BigDecimal)
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toCurrencyNumber(final CharSequence self) {
+        return toCurrencyNumber(self, Locale.getDefault());
+    }
+
+    /**
+     * Parses a CharSequence into a Number using the currency format of the 
given locale.
+     * The result is an exact {@link BigDecimal}.
+     * <pre class="groovyTestCase">
+     * assert '$1,234.50'.toCurrencyNumber(Locale.US) == 1234.50g
+     * </pre>
+     *
+     * @param self   a CharSequence
+     * @param locale the locale defining the currency format
+     * @return the parsed Number (a BigDecimal)
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toCurrencyNumber(final CharSequence self, final 
Locale locale) {
+        NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
+        if (nf instanceof DecimalFormat) ((DecimalFormat) 
nf).setParseBigDecimal(true);
+        try {
+            return nf.parse(self.toString());
+        } catch (ParseException e) {
+            throw new NumberFormatException("Unparseable currency: \"" + self 
+ "\"");
+        }
+    }

Review Comment:
   toCurrencyNumber currently relies on NumberFormat.parse(String), which can 
succeed on a numeric prefix and ignore trailing non-currency text. Also, the 
Javadoc promises an exact BigDecimal, but if the returned Number isn't a 
BigDecimal (e.g., non-DecimalFormat implementation), callers may get a 
different type. Consider trimming input, enforcing full-string consumption via 
ParsePosition, and normalizing the return value to BigDecimal.



##########
src/main/java/org/codehaus/groovy/runtime/StringGroovyMethods.java:
##########
@@ -3466,6 +3469,103 @@ public static BigInteger toBigInteger(final 
CharSequence self) {
         return new BigInteger(self.toString().trim());
     }
 
+    /**
+     * Parses a CharSequence into a Number using the given locale, honouring
+     * locale-specific grouping and decimal symbols. Unlike {@link 
#toBigDecimal(CharSequence)},
+     * parsing is lenient (a leading numeric prefix is accepted) and 
grouping-aware.
+     * <pre class="groovyTestCase">
+     * assert '1.234,5'.toNumber(Locale.GERMANY) == 1234.5
+     * </pre>
+     *
+     * @param self   a CharSequence
+     * @param locale the locale defining the number symbols
+     * @return the parsed Number
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toNumber(final CharSequence self, final Locale 
locale) {
+        try {
+            return 
NumberFormat.getNumberInstance(locale).parse(self.toString());
+        } catch (ParseException e) {
+            throw new NumberFormatException("Unparseable number: \"" + self + 
"\"");
+        }
+    }
+
+    /**
+     * Parses a CharSequence into a Number using the currency format of the 
default locale.
+     * The result is an exact {@link BigDecimal}.
+     *
+     * @param self a CharSequence
+     * @return the parsed Number (a BigDecimal)
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toCurrencyNumber(final CharSequence self) {
+        return toCurrencyNumber(self, Locale.getDefault());
+    }
+
+    /**
+     * Parses a CharSequence into a Number using the currency format of the 
given locale.
+     * The result is an exact {@link BigDecimal}.
+     * <pre class="groovyTestCase">
+     * assert '$1,234.50'.toCurrencyNumber(Locale.US) == 1234.50g
+     * </pre>
+     *
+     * @param self   a CharSequence
+     * @param locale the locale defining the currency format
+     * @return the parsed Number (a BigDecimal)
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toCurrencyNumber(final CharSequence self, final 
Locale locale) {
+        NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
+        if (nf instanceof DecimalFormat) ((DecimalFormat) 
nf).setParseBigDecimal(true);
+        try {
+            return nf.parse(self.toString());
+        } catch (ParseException e) {
+            throw new NumberFormatException("Unparseable currency: \"" + self 
+ "\"");
+        }
+    }
+
+    /**
+     * Parses a CharSequence into a Number using the percent format of the 
default locale.
+     * The percent value is unscaled (divided by 100).
+     *
+     * @param self a CharSequence
+     * @return the parsed Number
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toPercentNumber(final CharSequence self) {
+        return toPercentNumber(self, Locale.getDefault());
+    }
+
+    /**
+     * Parses a CharSequence into a Number using the percent format of the 
given locale.
+     * The percent value is unscaled (divided by 100).
+     * <pre class="groovyTestCase">
+     * assert '50%'.toPercentNumber(Locale.US) == 0.5
+     * </pre>
+     *
+     * @param self   a CharSequence
+     * @param locale the locale defining the percent format
+     * @return the parsed Number
+     * @throws NumberFormatException if the CharSequence cannot be parsed
+     *
+     * @since 6.0.0
+     */
+    public static Number toPercentNumber(final CharSequence self, final Locale 
locale) {
+        try {
+            return 
NumberFormat.getPercentInstance(locale).parse(self.toString());
+        } catch (ParseException e) {
+            throw new NumberFormatException("Unparseable percent: \"" + self + 
"\"");
+        }
+    }

Review Comment:
   toPercentNumber currently uses NumberFormat.parse(String), which can accept 
a valid percent prefix and ignore trailing junk. If the intent is to fail when 
the whole CharSequence isn't a valid percent, consider trimming and using 
ParsePosition to ensure the entire input is consumed before returning the 
parsed value.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to