How to parse only valid numbers in default locale using NumberFormat - java

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;
}

Related

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 this string in java?

How can a String be formatted in Java?
My String contains only numbers like "1234.0" and I want to return the formatted number.
For example, given the string "1234.0" the result should be the String "1234".
You can use regular expressions as well:
String n = "1234.0";
n.replaceAll("\\.0*$", "");
try {
String formatted = String.valueOf((int)Double.parseDouble("12345.0"));
} catch (ParseException e) {
// input is not a number
}
Use DecimalFormat like this:
DecimalFormat myFormatter = new DecimalFormat("####");
String output = myFormatter.format(value);
You can find more here

String to double and using IsNaN

I have a variable defined as String,
String totalweight;
This might take values '0.00','0.12'...any deciamls and also will have 'n/a' occasionally.
Now I have to format this field in such a way that if its not a number eg: 'n/a' leave it as such else format them like below.
public String getFmtWeight()
{
NumberFormat nf = NumberFormat.getNumberInstance();
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern("#0.00");
if(Double.isNaN(Double.parseDouble(totalweight)))
return totalweight;
else
return df.format(Double.parseDouble(totalweight));
// if(!totalweight.equals("n/a"))
// return df.format(Double.parseDouble(totalweight));
// else
// return "n/a";
}
This is breaking when n/a is cast to double throws exception. However commented portion would work. But I do not want to use it since 'n/a' may change in future with different string. Is there anyother way to achieve the same ?
One solution would be to use a try-catch to account for when parsing the string as a double fails, e.g.:
public String getFmtWeight()
{
NumberFormat nf = NumberFormat.getNumberInstance();
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern("#0.00");
try {
if(Double.isNaN(Double.parseDouble(totalweight)))
return totalweight;
else
return df.format(Double.parseDouble(totalweight));
} catch ( NumberFormatException ex ) {
/* thrown when the String can't be parsed as a double */
return totalweight; // if 'totalweight' is the String you want to parse
}
}
This will handle any string that cannot be parsed into a double using parseDouble.
You can use regular expression to validate.
NumberFormat nf = NumberFormat.getNumberInstance();
DecimalFormat df = (DecimalFormat)nf;
df.applyPattern("#0.00");
String totalweight = "n/a";
String pattern = "[0-9]*.[0-9]*";
boolean isNan = Pattern.matches(pattern, totalweight);
if(!isNan) {
System.out.println(totalweight);
}
else {
System.out.println(df.format(Double.parseDouble(totalweight)));
}
You can try this code

Checking if a given String is a valid currency using number format

I have below strings:
String str1 = "$123.00";
String str2 = "$(123.05)";
String str3 = "incorrectString";
I want to check and output like:
if(str1 is a valid currency){
System.out.println("Str1 Valid");
}else{
System.out.println("Str1 InValid");
}
if(str2 is a valid currency){
System.out.println("Str2 Valid");
}else{
System.out.println("Str2 InValid");
}
if(str3 is a valid currency){
System.out.println("Str3 Valid");
}else{
System.out.println("Str3 InValid");
}
UseCase: I am parsing a pdf using pdfbox. Given a searchterm say "abc", I want to read next token after the search term. For this purpose, I am searching for the search term in parsed pdf text and then reading the next token to that search term.
The token should be a valid currency. But there could be a case where in "abc" is present at two different places in a page with one having valid currency token next to it while the other not.
So I want to put in a check that if the token I am reading is not a valid currency token, break the loop and continue the search on the page.
I did it as below:
if (tokenRead.length() > 0) {
String temp = tokenRead.replace("$", "").replaceAll("\\(", "");
char checkFirstChar = temp.trim().charAt(0);
if (!(checkFirstChar >= '0' && checkFirstChar <= '9')) {
System.out.println("breaking");
break;
}
}
This works, but I believe there should be a elegant solution using NumberFormat.
Hence the question!
Thanks for reading!
NumberFormat has nothing out of the box for your use case.
A possible solution I could come up with is this:
Currency currency = Currency.getInstance(currentLocale);
String symbol = currency.getSymbol();
if(string.startsWith(symbol) || string.endsWith(symbol)){
System.out.println("valid");
}else{
System.out.println("invalid");
}
But then you still need to check if the rest of the string can be parsed to a number.
Therefore I recommend to have a look at Apache Commons Currency Validator, it may fit your needs:
#Test
public void test() {
BigDecimalValidator validator = CurrencyValidator.getInstance();
BigDecimal amount = validator.validate("$123.00", Locale.US);
assertNotNull(amount);
//remove the brackets since this is something unusual
String in = "$(123.00)".replaceAll("\\(", "").replace(')', ' ').trim();
amount = validator.validate(in, Locale.US);
assertNotNull(amount);
amount = validator.validate("invalid", Locale.US);
assertNull(amount);
}
You could try DecimalFormat. It allows you to handle positive and negative value patterns separately using ;:
List<String> list = new ArrayList<>();
list.add("$123.00");
list.add("$(123.05)");
list.add("incorrectString");
NumberFormat nf = new DecimalFormat("¤#.00;¤(#.00)", new DecimalFormatSymbols(Locale.US));
try {
for(String str : list){
nf.parse(str);
}
} catch (ParseException e) {
System.out.println(e.getMessage());
}

Why does DecimalFormat allow characters as suffix?

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.

Categories

Resources