Why does DecimalFormat allow characters as suffix? - java

I'm using DecimalFormat to parse / validate user input. Unfortunately it allows characters as a suffix while parsing.
Example code:
try {
final NumberFormat numberFormat = new DecimalFormat();
System.out.println(numberFormat.parse("12abc"));
System.out.println(numberFormat.parse("abc12"));
} catch (final ParseException e) {
System.out.println("parse exception");
}
Result:
12
parse exception
I would actually expect a parse exception for both of them. How can I tell DecimalFormat to not allow input like "12abc"?

From the documentation of NumberFormat.parse:
Parses text from the beginning of the given string to produce a number. The method may not use the entire text of the given string.
Here is an example that should give you an idea how to make sure the entire string is considered.
import java.text.*;
public class Test {
public static void main(String[] args) {
System.out.println(parseCompleteString("12"));
System.out.println(parseCompleteString("12abc"));
System.out.println(parseCompleteString("abc12"));
}
public static Number parseCompleteString(String input) {
ParsePosition pp = new ParsePosition(0);
NumberFormat numberFormat = new DecimalFormat();
Number result = numberFormat.parse(input, pp);
return pp.getIndex() == input.length() ? result : null;
}
}
Output:
12
null
null

Use the parse(String, ParsePosition) overload of the method, and check the .getIndex() of the ParsePosition after parsing, to see if it matches the length of the input.

Related

Parse 2.000,00 to 2000 and 2.000,15 to 2000.15

I am struggling with formatting numbers in java.
My input format looks like this (and I cannot change that): 2.000,15
and the output should look like this: 2000.15
In case of only 0 after the comma the output should look like this: 2000
The input is given as a String.
I've already tried to use a DecimalFormat but this only leads to IllegalArgumentException
DecimalFormat decimalFormat = (DecimalFormat) NumberFormat.getInstance(Locale.ENGLISH);
decimalFormat.setMinimumFractionDigits(0);
decimalFormat.setMaximumFractionDigits(2);
decimalFormat.setGroupingUsed(false);
return decimalFormat.format(Double.parseDouble(characteristicValue));
give this a try:
NumberFormat fmt = NumberFormat.getInstance(Locale.GERMAN);
try {
BigDecimal bd = new BigDecimal(fmt.parse("2.000,15").toString());
System.out.println(bd.toString()); // output: 2000.15
} catch (ParseException e) {
//ex handling
}
You can try the following:
Choose a number format that uses dot-separated thousands-place separators.
Set the minimum significant figures for the decimal (fraction) place.
There is no need to set-up a format that already exists in Java's SDK.
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class FormattingNumbers {
static NumberFormat inputFormat = NumberFormat.getNumberInstance(Locale.GERMAN);
static NumberFormat outputFormat = NumberFormat.getNumberInstance(Locale.US);
static {
inputFormat.setMinimumFractionDigits(2);
outputFormat.setMinimumFractionDigits(2);
}
public static void main(String[] args) throws ParseException {
String[] numbers = { "2.000,00", "2.000,15" };
for (String number : numbers) {
System.out.println(outputFormat.format(inputFormat.parse(number)));
}
}
}
Output:
2,000.00
2,000.15
Note: Here is a list of countries using decimal comma.
You had the right tool, but you don't need to get an instance of DecimalFormat, you can just create your own.
import java.text.DecimalFormat;
class Playground {
public static void main(String[ ] args) {
String pattern = "###,###.###";
DecimalFormat decimalFormat = new DecimalFormat(pattern);
String format = decimalFormat.format(2000.15);
System.out.println(format);
}
}

How to format currency with number format classes

I am new in Android development and i am stuck at a place. I want to format my currency, I am setting to show without decimal places and with commas.
Example: right now it's showing like 23000.00. But I want the currency like 23,000; how can I do that?
I tried the formatter classes but that doesn't help me.
This is how it's set now.
public class CurrencyFormatter {
public static String setsymbol(BigDecimal data, String currency_symbol)
{
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.ENGLISH);
format.setCurrency(Currency.getInstance(currency_symbol));
String result=data+" "+" دينار";
return result;
}
}
I expect output to be (arabic text)23,000 instead of (arabic test)23000.00
Basically, you need a currency formatter object.
NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance(currentLocale);
After that you can format an amount of money:
Double currencyAmount = new Double(23000.00);
String formattedOutput = currencyFormatter.format(currencyAmount);
There are more options and explanations available here on Oracle's reference document: https://docs.oracle.com/javase/tutorial/i18n/format/numberFormat.html
check this
NumberFormat format = NumberFormat.getCurrencyInstance(Locale.getDefault());
format.setCurrency(Currency.getInstance("USA"));
String result = format.format(1234567.89);
This is the format set of usa you can change with your country code
reference check description here
Try this, it will show in this format 23,000 without decimal points, It will show thousand separator in the number.
String result = null;
try {
// The comma in the format specifier does the trick
result = String.format("%,d", Long.parseLong(data)); // use this result variable where you want to use.
result = result + " " + " دينار"; // to append arabic text, do as you were doing before.
} catch (NumberFormatException e) {
}

How to format a math expression inside a text field?

I'm creating a Calculator software. In the text field as I'm typing, the whole expression appears as one string (and I want to keep it this way). Here's a demo:
I want it to be formatted like this:
NUMBERS - ###.###.###,###### (Grouping them into 3 digit groups, displaying fractions ONLY when needed and only up to 6 digits.)
Operators and Parenthesis - ###×(###-###)/### (Should not cause any formatting errors or problems. I don't care if there is or there isn't a space inbetween the numbers and operators/parenthesis.)
Here's the above example in the correct format:
1.000×(5-3)/2
I also want it to automatically update the formatting as I'm typing.
Sofar I tried using JFormattedTextField with MaskFormatters and NumberFormat but neither of them worked as (described above) I wanted to.
NumberFormat version.
public class Frame {
private NumberFormat numberFormat = NumberFormat.getInstance();
private JFormattedTextField textField = new JFormattedTextField(numberFormat);
}
MaskFormatter version.
public class Frame {
private MaskFormatter maskFormat;
private JFormattedTextField textField;
public Frame() {
try {
maskFormat = new MaskFormatter("###.###.###,######");
} catch (ParseException e) {
e.printStackTrace();
}
textField = new JFormattedTextField(maskFormat);
}
}
I managed to format the result using DecimalFormat but I don't want only the result to be formatted.
Formatting the result.
DecimalFormat resultFormat = new DecimalFormat("###,###,###.######");
String result = resultFormat.format(Parser.evaluate(expression));
textField.setText(result);
When I calculate 5/3 the result is:
Just as I wanted.
Sorry for such a detailed and long post, any help is greatly appreciated!
Try this.
DecimalFormat resultFormat = new DecimalFormat("###,###,###.######");
Pattern numberPattern = Pattern.compile("\\d+(\\.\\d+)?");
String s = "1000×(5-3)/2";
Matcher m = numberPattern.matcher(s);
StringBuffer sb = new StringBuffer();
while (m.find()) {
double value = Double.parseDouble(m.group());
String formatted = resultFormat.format(value);
m.appendReplacement(sb, formatted);
}
m.appendTail(sb);
System.out.println(sb);
// -> 1,000×(5-3)/2

How to parse only valid numbers in default locale using NumberFormat

I'm using a NumberFormat instance to parse text using default locale.
If a string is not a valid numeric value, I have to return 0. The problem is that parse method,according to Javadocs:
Parses text from the beginning of the given string to produce a
number. The method may not use the entire text of the given string.
So, if I parse (I'm using italian locale) "BAD 123,44" I correctly get a ParseException and return 0, but if I parse "123,44 BAD", I get a value of 123.44, while I have to return 0 in this case.
And worse, if I parse "123.44 BAD", I get value 12344!
class RateCellReader {
public static final NumberFormat NUMBER_FORMAT =
NumberFormat.getNumberInstance(Locale.getDefault());
...
try {
number = NUMBER_FORMAT.parse(textValue);
} catch (ParseException e) {
number = 0;
}
...
}
How can I do an exact parse of text, or check if text correctly represent a number in default locale?
EDIT:
Getting inspired by the response linked by #yomexzo, I changed my code like this:
class RateCellReader {
public static final NumberFormat NUMBER_FORMAT =
NumberFormat.getNumberInstance(Locale.getDefault());
...
ParsePosition pos = new ParsePosition(0);
number = NUMBER_FORMAT.parse(textValue,pos);
if (textValue.length() != pos.getIndex())
number = 0;
...
}
How about this
boolean isValid;
try {
Number n = NUMBER_FORMAT.parse(s1);
String s2 = NUMBER_FORMAT.format(n);
isValid = s1.equals(s2);
}catch(ParseException e) {
isValid = false;
}

Best way to convert Locale specific String to BigDecimal

I have to convert a German locale formatted String to a BigDecimal. However, I'm struggling with the best solution.
The following code shows my problem:
String numberString = "2.105,88";
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
try {
Number parsed = nf.parse(numberString);
BigDecimal bd1 = new BigDecimal(parsed.toString());
System.out.println(bd1.toString());
BigDecimal bd2 = new BigDecimal(parsed.doubleValue());
System.out.println(bd2);
BigDecimal bd3 = new BigDecimal(numberString);
System.out.println(bd3);
} catch (ParseException e) {
e.printStackTrace();
}
The outpout of this is
2105.88
2105.8800000000001091393642127513885498046875
Exception in thread "main" java.lang.NumberFormatException
at java.math.BigDecimal.(Unknown Source)
at java.math.BigDecimal.(Unknown Source)
at test.BigDecimalTest.main(BigDecimalTest.java:22)
The first output is correct, but it doesn't really make sense to convert a String to a Number (Double to be precise), then back to a String again and then into a specific type of Number, BigDecimal.
The second output is incorrect, but could be solved by setting the scale of the BigDecimal. However, the amount of digits is not always known.
The third output is obviously not what I'm looking for.
My question: What would be the best way? Are there better ways to do this?
It seems like there is no other way since java.Lang.Number doesn't have a method which returns a BigDecimal type. Anyway it makes sense because BigDecimal only accepts strings which are properly formatted not like "2.105,88" but like "2105.88".
Let me show your my code:
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;
public class JavaMain {
public static void main(String[] args) {
String numberString = "2.105,88";
//using casting
try {
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.GERMAN);
df.setParseBigDecimal(true);
BigDecimal bd = (BigDecimal) df.parseObject(numberString);
System.out.println(bd.toString());
} catch (ParseException e) {
e.printStackTrace();
}
//your way short version
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
try {
BigDecimal bd1 = new BigDecimal(nf.parse(numberString).toString());
System.out.println(bd1.toString());
} catch (ParseException e) {
e.printStackTrace();
}
String numberStringFixed = "2105.88";
//direct string formatted
System.out.println(new BigDecimal(numberStringFixed));;
//direct but erroneous way if the string is not formatted
System.out.println(new BigDecimal(numberString));;
}
}
I hope this helps!
DecimalFormat has a method called setParseBigDecimal that causes parse() to return a BigDecimal. You just need to cast the returned Number.
String numberString = "2.105,88";
NumberFormat nf = NumberFormat.getInstance(Locale.GERMAN);
if (nf instanceof DecimalFormat) {
DecimalFormat df = (DecimalFormat) nf;
df.setParseBigDecimal(true);
BigDecimal parsed = (BigDecimal) df.parse(numberString);
System.out.println(parsed);
}
Output:
2105.88
setParseBigDecimal was introduced in Java 1.5.

Categories

Resources