I have a string that I'm trying to parse into a BigDecimal. I'm using the following regex to strip all non currency symbols with the exception of -,.()$. Once it has been stripped, I'm then trying to create a BigDecimal with the remaining value. The problem begins when a negative value comes across in brackets. Does anybody have any suggestions on how to repair this instance?
(1000.00) fails
I'm assuming I must somehow convert the brackets to a negative sign.
code sample.
public BigDecimal parseClient(Field field, String clientValue, String message) throws ValidationException {
if (clientValue == null) {
return null;
}
try {
clientValue = clientValue.replaceAll( "[^\\d\\-\\.\\(\\)]", "" );
return new BigDecimal(clientValue.toString());
} catch (NumberFormatException ex) {
throw new ValidationException(message);
}
}
You will need to detect the ( and ) characters yourself, then strip them out, create a BigDecimal from the rest of the string, and negate it.
if (clientValue.startsWith('(') && clientValue.endsWith(')'))
{
return new BigDecimal(clientValue.substring(1, clientValue.length() - 1)).negate();
}
else
{
return new BigDecimal(clientValue);
}
What makes you think parentheses are correctly interpreted by BigDecimal? (1000.00) is incorrect input according to the documentation. You must use - symbol (-1000.00). Supported format is strictly defined in JavaDoc. In general it's optional symbol (+ or -) followed by digits, dot (.) and exponent.
For example this is valid input: -1.1e-10.
DecimalFormat is a more appropriate tool for the job:
DecimalFormat myFormatter = new DecimalFormat("¤#,##0.00;(¤#,##0.00)");
myFormatter.setParseBigDecimal(true);
BigDecimal result = (BigDecimal) myFormatter.parse("(1000.00)");
System.out.println(result); // -1000.00 for Locale.US
System.out.println(myFormatter.parse("($123,456,789.12)")); // -123456789.12
As you can see, not only will it deal with negative patterns, but also with currency signs, decimal and grouping separators, localization issues, etc.
Take a look at The Java Tutorials: Customizing Formats for further info.
Related
I'm taking a value from the mobile application which I'm getting in string format something like "$000"(which actually $0.00 ) similarly I want to convert all the value into two decimal place say if I get "$279"(which is in application actually $2.79)
I don't know the correct approach because further in I have compair this value to some other string.
so I want to keep this as String but at the same time I want to put decimal after two place always whatever the number.
I tried to Decimal formatter for money but gave me "object as a number format" exception
sends
String accLastFourDigits, getCurrAmt, currAmt;
getCurrAmt = getDriver().findElement(by("overview.current_balance")).getText();
DecimalFormat money = new DecimalFormat("$0.00");
currAmt = money.format(getCurrAmt);
You could use builtin NumberFormat provided by JAVA to parse different country Currencies as shown below. Also I am dividing the resulting number by 100, so as to satisfy the requirement, that $978 is read as 9.78.
NumberFormat usFormat = NumberFormat.getCurrencyInstance(Locale.US);
String currencyValue = "$100";
try {
System.out.println(usFormat.parse(currencyValue).intValue()/100);
}catch(ParseException e) {
e.printStackTrace();
}
Here, I am setting the currency to US and then parsing a string with dollar sign.
You could also use the format method of NumberFormat to print the currency value in respective currency formats, as shown below
NumberFormat usFormat = NumberFormat.getCurrencyInstance(Locale.US);
String currencyValue = "$100";
try {
Number value = usFormat.parse(currencyValue).intValue()/100;
System.out.println("Number value : " + value);
System.out.printf("In Currency : "+usFormat.format(value));
}catch(ParseException e) {
e.printStackTrace();
}
You have this exception because format method expect number type argument. What you need to do then is to remove all non digits characters from the input string
getCurrAmt = getCurrAmt.replaceAll("[^\\d.]", ""); // please note that replaceAll method has poor performance
and parse it to Integer when calling format method
money.format(Integer.parseInt(getCurrAmt))
As pointed out replaceAll method is not very efficient because it needs to compile Pattern every single time and it's better to use Matcher - you can read about this in this topic:
String replaceAll() vs. Matcher replaceAll() (Performance differences)
How about this?
String inputStr = "$279";
NumberFormat usCurrency = NumberFormat.getCurrencyInstance(Locale.US);
usCurrency.setParseIntegerOnly(true);
long num = (Long)usCurrency.parse(inputStr);
BigDecimal amount = new BigDecimal(num);
amount = amount.scaleByPowerOfTen(-2);
log.info("amount: {}", usCurrency.format(amount));
Is there a Java parsing library similar to DecimalFormat? I am unable to do what I want with DecimalFormat and regular expressions.
I need to be able to:
Parse only an integer (DecimalFormat needs more settings than just pattern)
Parse decimal (precise no rounding)
Parse numbers like 123,456.789. (DecimalFormat for ###,###.### accepts "123456789" as well)
You could try treating it like a String and tokenizing it.
str.split("\\.") will split out the decimal side and then substring it to your precision, then on the number side you could split(",")
This is quite a bit of manual parsing work though...
I would use Regexp and NumberFormat:
Map<Pattern,NumberFormat> POSSIBLE_FORMATS = ...;
String input = ...;
Number value = null;
for (Map.Entry<Pattern,NumberFormat> possible : POSSIBLE_FORMATS.entrySet()) {
if (possible.getKey().matcher(input).matches()) {
value = possible.getKeValue().parse(input);
break;
}
}
if (value == null) {
throw new IllegalArgumentExcption("no valid input format: " + input);
}
In my program I read input from the console and determine whether it is a number or not. Numbers can be any decimal +-. For instance having 123.18p18 is not allowed since there is a nondigit in there, same with -123.18p18. The bad way of doing this (which I am currently doing) is checking if it is a double and catching exceptions, but since I am just parsing a string I think regex is far better to use here. This is my first day in its use (regex) and it seems like an alien language.
I came up with ".*\\D+.*" but that only handles positive numbers.
Edit: Integers are also acceptable.
You are looking for:
"^[+-]?\\d+([.]\\d+)?$"
Optional plus or minus in the beginning, followed by at least one digit. Before the end of the string there can optionally be one dot followed by at least one digit.
To solve your initial problem, you can use the java.util.Scanner class. It provides methods for testing whether the next input is an integer, double, etc., or even testing whether the next input conforms to a given regular expression.
import java.util.Scanner;
//...
Scanner s = new Scanner(System.in);
while ( s.hasNext() ) {
if ( s.hasNextInt() ) {
int i = s.readInt();
// Some work.
} else if ( s.hasNextDouble() ) {
double d = s.nextDouble();
// Some work.
} else if ( s.hasNext(regex) ) {
String t = s.next(regex);
// Some work.
}
// etc.
}
The following regex might work for you;
It defines a pattern which starts with either a + or - followed by zero or more digits and if there is a decimal point, then it must be followed by at least one digit
"^[+-]?\\d+(?:\\.?\\d+)$"
Try double doubleInstance = Double.parseDouble(string); and proceed...
I'm getting NumberFormatException when I try to parse 265,858 with Integer.parseInt().
Is there any way to parse it into an integer?
Is this comma a decimal separator or are these two numbers? In the first case you must provide Locale to NumberFormat class that uses comma as decimal separator:
NumberFormat.getNumberInstance(Locale.FRANCE).parse("265,858")
This results in 265.858. But using US locale you'll get 265858:
NumberFormat.getNumberInstance(java.util.Locale.US).parse("265,858")
That's because in France they treat comma as decimal separator while in US - as grouping (thousand) separator.
If these are two numbers - String.split() them and parse two separate strings independently.
You can remove the , before parsing it to an int:
int i = Integer.parseInt(myNumberString.replaceAll(",", ""));
If it is one number & you want to remove separators, NumberFormat will return a number to you. Just make sure to use the correct Locale when using the getNumberInstance method.
For instance, some Locales swap the comma and decimal point to what you may be used to.
Then just use the intValue method to return an integer. You'll have to wrap the whole thing in a try/catch block though, to account for Parse Exceptions.
try {
NumberFormat ukFormat = NumberFormat.getNumberInstance(Locale.UK);
ukFormat.parse("265,858").intValue();
} catch(ParseException e) {
//Handle exception
}
One option would be to strip the commas:
"265,858".replaceAll(",","");
The first thing which clicks to me, assuming this is a single number, is...
String number = "265,858";
number.replaceAll(",","");
Integer num = Integer.parseInt(number);
Or you could use NumberFormat.parse, setting it to be integer only.
http://docs.oracle.com/javase/1.4.2/docs/api/java/text/NumberFormat.html#parse(java.lang.String)
Try this:
String x = "265,858 ";
x = x.split(",")[0];
System.out.println(Integer.parseInt(x));
EDIT :
if you want it rounded to the nearest Integer :
String x = "265,858 ";
x = x.replaceAll(",",".");
System.out.println(Math.round(Double.parseDouble(x)));
I am having problems using DecimalFormat when I am going to print out coefficients after a regression.
Here is the part of the code that is facing problems;
DecimalFormat twoDForm = new DecimalFormat("0.00");
private double s(double d){
return Double.valueOf(twoDForm.format(d));
}
and here is the error message in eclipse;
Exception in thread "main" java.lang.NumberFormatException: For input string: "0,16"
at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
at java.lang.Double.valueOf(Unknown Source)
at model.ARF2.s(ARF2.java:126)
at model.ARF2.printBestModel(ARF2.java:114)
at testing.testclass3.bestForecastingModel(testclass3.java:69)
at testing.testclass3.main(testclass3.java:36)
Please let me know if anyone has any surgestions on how to fix the code. I want two decimals on my coefficients.
Thank you
Lars
use:
DecimalFormat twoDForm = new DecimalFormat("#.##");
DecimalFormatSymbols dfs = new DecimalFormatSymbols();
dfs.setDecimalSeparator('.');
twoDForm.setDecimalFormatSymbols(dfs);
http://download.oracle.com/javase/1.4.2/docs/api/java/text/DecimalFormat.html
The following excerpt appears to be part of your problem:
To obtain a NumberFormat for a
specific locale, including the default
locale, call one of NumberFormat's
factory methods, such as
getInstance(). In general, do not call
the DecimalFormat constructors
directly, since the NumberFormat
factory methods may return subclasses
other than DecimalFormat. If you need
to customize the format object, do
something like this:
NumberFormat f = NumberFormat.getInstance(loc);
if (f instanceof DecimalFormat) {
((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
}
You may want to use the applyPattern method:
applyPattern
public void applyPattern(String
pattern) Apply the given pattern to
this Format object. A pattern is a
short-hand specification for the
various formatting properties. These
properties can also be changed
individually through the various
setter methods. There is no limit to
integer digits are set by this
routine, since that is the typical
end-user desire; use setMaximumInteger
if you want to set a real value. For
negative numbers, use a second
pattern, separated by a semicolon
Example "#,#00.0#" -> 1,234.56
This means a minimum of 2 integer
digits, 1 fraction digit, and a
maximum of 2 fraction digits.
Example: "#,#00.0#;(#,#00.0#)" for
negatives in parentheses.
In negative patterns, the minimum and
maximum counts are ignored; these are
presumed to be set in the positive
pattern.
Throws: NullPointerException - if
pattern is null
IllegalArgumentException - if the
given pattern is invalid.
You are encountering an i18n issue. DecimalFormat is using your default locale which specifies the decimal separator as ,. However, the Double.valueOf does not use the locale. It always expects that the decimal separator is ..
If you want to parse a string formatted with DecimalFormat then you need to use DecimalFormat.parse
I think what you intended to do is:
private static String s(double d) {
return twoDForm.format(d);
}
Are you trying to format the number? Or round it? If you're formatting it, shouldn't your "s" method (bad name IMO, btw, but it's private, so it's your call) return a java.lang.String instead of a double?
Check your Locale.
DecimalFormat twoDForm = new DecimalFormat("0.00");
private double s(double d){
String doubleString = displayNumberAmount(twoDForm.format(d));
return Double.valueOf(doubleString);
}
public static String displayNumberAmount(String amount) {
NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.CANADA_FRENCH);
Number number = 0;
try {
number = numberFormat.parse(amount);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return String.format(Locale.US, "%1$,.2f", number);
}