In Java, I am trying to get DecimalFormat to enforce the sign on an exponent sign. When it is positive I need a plus sign to appear. From what I have read this seems like a no brainer, but for myself it always throws up an error. I appreciate that there may be other methods to achieve my goal, but I would like to understand why in this specific method the error is occurring.
Double result = 123.456;
String sresult;
//This works
NumberFormat formatter = new DecimalFormat("0.00000E00");
sresult = formatter.format(result);
System.out.println(sresult); //1.23456E02
//This doesn't work
formatter = new DecimalFormat("0.00000E+00"); //Want to enforce the sign to appear
sresult = formatter.format(result);
System.out.println(sresult); //Expected 1.23456E+02 but error occurs
The error which is thrown up:
Exception in thread "main" java.lang.IllegalArgumentException:
Malformed exponential pattern "0.00000E+00"
at java.text.DecimalFormat.applyPattern(Unknown Source)
at java.text.DecimalFormat.(Unknown Source)
at deccheck.main(deccheck.java:13)
I appreciate any insight.
Thanks,
Mark
I would like to extend the solution by j flemm. The "E" and "-" are no constants, they can be set as DecimalFormatSymbols. Therefore the substitutions must respect this:
public static String hoola(final String s, final DecimalFormatSymbols symbols) {
String result;
final String expo = symbols.getExponentSeparator();
final char minus = symbols.getMinusSign();
if (!s.contains(expo + minus)) { // don't blast a negative sign
result = s.replace(expo, expo + '+');
} else {result=s;}
return result;
}
/**
* #param args
*/
public static void main(final String[] args) {
final DecimalFormat decForm = (DecimalFormat) NumberFormat
.getInstance(Locale.GERMAN);
final DecimalFormatSymbols newSymbols = new DecimalFormatSymbols(
Locale.GERMAN);
newSymbols.setExponentSeparator("*10^");
newSymbols.setMinusSign('\u2212');
decForm.setDecimalFormatSymbols(newSymbols);
decForm.applyPattern("0.00000E00");
System.out.println(hoola(decForm.format(1234.567), decForm
.getDecimalFormatSymbols()));
System.out.println(hoola(decForm.format(000.00567), decForm
.getDecimalFormatSymbols()));
}
Result is:
1,23457*10^+03
5,67000*10^−03
Easy way:
formatter = new DecimalFormat("0.00000E00"); // Want to enforce the sign to appear
sresult = formatter.format(result);
if (!sresult.contains("E-")) { //don't blast a negative sign
sresult = sresult.replace("E", "E+");
}
System.out.println(sresult);
Outputs 1.23456E+02 for your example.
But I don't believe there's a way to do it from inside the DecimalFormat pattern. Or at least the javadoc doesn't indicate there is one.
Edit: trashgod brings up a good point. You'd probably want to get positive and negative signs from DecimalFormatSymbols if you plan on localizing this to different regions.
Edit 2: Andrei pointed out that E is also a localization variable. Shows what I know about localization.
I don't think the '+' character is an accepted character in a pattern (after studying the javadocs). And the pattern for for the exponential part si described as:
Exponent:
E MinimumExponent
MinimumExponent:
0 MinimumExponent(opt)
If you add anything there it will confuse the parser.
I think your only option is to give it the normal pattern (without '+') and then get the String and use regex to add the '+' there.
sresult = formatter.format(result);
sresult = sresult.replaceAll("E([^\\-]+)", "E+$1");
The best option might be extending DecimalFormat and doing this in the overwritten format method
#j flemm's approach is appealing because "Negative exponents are formatted using the localized minus sign, not the prefix and suffix from the pattern."—DecimalFormat.
Related
I have tried
System.out.println(myLorry.toString(registration, myCar.calcCharge()));
which outputs
Registration: TA17 NDD Charge: 7.0
I want my program to output
Registration: TA17 NDD Charge: £7.00
How can I format this correctly?
EDIT:
Why doesn't formatting work correctly? It says it's expecting two parameters but can only find one. I need to call objects using the toString method.
System.out.printf("%s £%.2f" ,myCar.toString(registration, myCar.calcCharge()));
like #davidxxx suggest in comment you can use
DecimalFormat d = new DecimalFormat("'£'0.00");
System.out.println(d.format(7.0));
Output
£7,00
If you have a problem with dot(.) and comma(,) then you can use DecimalFormatSymbols :
DecimalFormat d = new DecimalFormat("'£'0.00");
DecimalFormatSymbols sym = DecimalFormatSymbols.getInstance();
sym.setDecimalSeparator('.');
d.setDecimalFormatSymbols(sym);
one solution is to use the printf.
e.g.
double value = 7.0;
System.out.printf("%s%.2f","£", value);
output:
£7.00
In fact you should consider two things :
formatting the number value with the fixed number of digits for the floating part.
setting the decimal separator character.
The second point may matter as according to the locale set by the JVM, you could get a distinct result : £7.00 or £7,00
So, you could specify the "£0.00" pattern in DecimalFormat and create the DecimalFormat instance with a specific DecimalFormatSymbols that ensures that you will use as decimal symbol the . character.
You could do it for example :
float f = 7;
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
otherSymbols.setDecimalSeparator('.');
NumberFormat formatter = new DecimalFormat("£0.00", otherSymbols);
String valueFormated = formatter.format(f);
But in fact a more simple way would be to use the String.format() method by specifying both the expected pattern (two digits for the floating part) and a Locale that uses the . as decimal separator :
float f = 7;
String valueFormated = String.format(Locale.US, "£%.2f", f);
Solved it! I was looking in completely the wrong part of my program, here is my solution:
String toString(String rn, double calcCharge)
{
DecimalFormat d = new DecimalFormat("£0.00");
return "Registration: " + rn + " Charge: " + d.format(calcCharge());
}
I had to modify a class that my subclasses inherited from.
is there a class in Java that lets you format a number like "102203345.32" to this "102.203.345,32" and return a string type?
I would like to obtain a String where the thousands are separated by the '.' and the decimals are separated by a comma ','.
Could someone help me please? I found a class DecimalFormat and I tried to customize it:
public class CustomDecimalFormat {
static public String customFormat(String pattern, double value ) {
DecimalFormat myFormatter = new DecimalFormat(pattern);
String output = myFormatter.format(value);
return output;
}
}
but when I call the customFormat method like this: CustomDecimalFormat.customFormat("###.###,00") I get an exception...
What should I do?
Thanks!
Be sure to read and understand the Special Pattern Characters section of the Javadoc, especially this note:
The characters listed here are used in non-localized patterns. Localized patterns use the corresponding characters taken from this formatter's DecimalFormatSymbols object instead, and these characters lose their special status.
If you have done that, it should be clear to you that you must use the appropriate constructor and supply the appropriately configured separator/grouping chars, whereas in the pattern itself the dot and the comma have a special meaning.
All the complexity above is there for your convenience, actually: it allows you to customize the number format and have it localized.
Here's a code sample which worked for me:
final DecimalFormatSymbols syms = new DecimalFormatSymbols();
syms.setDecimalSeparator(',');
syms.setGroupingSeparator('.');
DecimalFormat myFormatter = new DecimalFormat("###,###.00", syms);
System.out.println(myFormatter.format(1234.12));
You can also use a variant where you apply the localized pattern, for more intuitive code:
final DecimalFormatSymbols syms = new DecimalFormatSymbols();
syms.setDecimalSeparator(',');
syms.setGroupingSeparator('.');
DecimalFormat myFormatter = new DecimalFormat("", syms);
myFormatter.applyLocalizedPattern("###.###,00");
System.out.println(myFormatter.format(1234.12));
First of all,
you misplaced the comma and decimal points. Your format should be : ###,###.00 instead of ###.###,00 ...
Also check with your Locale, it has an effect on the format. See the link below.
http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
You can try GERMAN number format
NumberFormat.getNumberInstance(Locale.GERMAN).format(102203345.32)
I'm trying to ensure that a given string is a valid double. Most answers to this sort of question suggest using Double.parseDouble(inputString). However this isn't as robust as I'd hope. For instance if I enter a String such as "1one" Double.parseDouble("1one") will output "1" as opposed to returning an exception for an invalid double.
I've tried to get around this by iterating over the string and ensuring that every number is a digit:
for (int i = 0; i < number.length(); i++) {
previousChar = number.charAt(i);
if (!Character.isDigit(number.charAt(i))
&& number.charAt(i) != '.'
&& number.charAt(i) != ',') {
return null;
}
}
But for cases such as "20..02" or "20,,02" this will simply return 20. I was wondering what the best way to account for cases such as these would be.
Good question. Depending on the users, you may need to be careful of differences between locales. Some places use , as a thousand separator others as a decimal point. You can find the locale-specific value using:
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance();
DecimalFormatSymbols symbols = formatter.getDecimalFormatSymbols();
char decimalSeparator = symbols.getDecimalSeparator();
I would suggest writing a regular expression for your exact requirement rather than doing the matching manually. Remember to escape . if you want it to match . and not "any character".
Alternatively, you may be able to use parseDouble which does seem to throw an exception for "1one" after all:
System.out.println(Double.parseDouble("1one"));
For me, it produces:
Exception in thread "main" java.lang.NumberFormatException: For input string: "1one"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1241)
at java.lang.Double.parseDouble(Double.java:540)
You could use the Validator framework and use the DoubleValidator from commons-validator.
DoubleValidator validator = DoubleValidator.getInstance();
validator.validate("1one");
Parsing strings to doubles is fraught with danger. For example, in France, 1,234 is a number just a little greater than 1. They use . to separate round thousands and , to denote the start of the decimal portion.
The best way to check if a string is a valid number is to use NumberFormat to attempt to parse it and treat any exceptions thrown as an indication that the string is not a valid number. NumberFormat allows you to associate a locale:
NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH/*for example*/);
double myNumber = nf.parse(myString); /*will throw an exception if not valid*/
I would use Double.parseDouble, because, contrary to what you believe, it does throw a NumberFormatException for 1one.
public class k {
public static void main(String argv[]) {
double d = Double.parseDouble("1one");
}
}
Output:
Exception in thread "Main Thread" java.lang.NumberFormatException: For input string: "1one"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1222)
at java.lang.Double.parseDouble(Double.java:510)
at k.main(k.java:3)
If I wanted to allow both , and . and not just the decimal point specified by the locale, I would replace any , and . with the locale specified decmial point.
Using a simple regex, you can check if it contains any non numerical characters like so:
String input = "1one2";
String numerical = input.replaceAll("[^0-9.]", "");
if (input.equals(numerical)) // If you remove all non numbers, still the same string
After which you can parse it for a double.
I have a monetary amount that is entered by a user and want to validate it. I have written a JSF validator but am having trouble getting this to work in all circumstances. Here is my scenario:
I have users in different Locales and therefore I need to cope with the various methods of input and want to allow the following
English
1234
1,234
1234.56
1,234.5
German & Spanish
1234
1.234
1234,56
1.234,5
French
1234
1 234
1234,56
1 234,5
My problem is with French as options 2 & 4 are seen as invalid using this code as the parsing stops at the space.
public void validate(final FacesContext pContext,
final UIComponent pComponent,
final Object pValue) {
boolean isValid = true;
final Locale locale = (Locale)pComponent.getAttributes().get(USERS_LOCALE);
final Currency currency = (Currency)pComponent.getAttributes().get(CURRENCY);
final NumberFormat formatter = NumberFormat.getNumberInstance(locale);
formatter.setGroupingUsed(true);
formatter.setMinimumFractionDigits(currency.getDefaultFractionDigits());
formatter.setMaximumFractionDigits(currency.getDefaultFractionDigits());
final ParsePosition pos = new ParsePosition(0);
final String stringValue = (String)pValue;
if (pos.getIndex() != stringValue.length() || pos.getErrorIndex() != -1) {
isValid = false;
}
...
I also want to ensure that the following are treated as invalid but they all parse successfully (except for French of course)
1,234,9.56 (Invalid grouping)
1,234.567 (too many decimal places for the currency)
Any help will be much appreciated
Ian
The French thousands' separator is actually a non-breaking space, \u00a0. If your input uses a regular space you can change the input:
input = input.replace(' ', '\u00a0');
Another thing you can do is change the grouping symbol to a regular space:
DecimalFormat decimalFormatter = (DecimalFormat) formatter;
DecimalFormatSymbols symbols = decimalFormatter.getDecimalFormatSymbols();
symbols.setGroupingSeparator(' ');
decimalFormatter.setDecimalFormatSymbols(symbols);
Can't recommend this, though. The new formatter won't accept numbers that use a non-breaking space as the grouping character.
I'm trying to format a BigDecimal value by using methods of DecimalFormat.format().
My problem, is I don't know how to set DecimalFormats DecimalFormatSymbol to format text without any grouping separators.
I'd like to know how to set a grouping symbol and use the format methods. I know how to do it differently by using replace or others methods but it's not what I want.
So I need to know how to set an empty character as grouping operator.
Example:
DecimalFormat dec = new DecimalFormat();
DecimalFormatSymbols decFS = new DecimalFormatSymbols();
decFS.setGroupingSeparator( '\0' );
dec.setDecimalFormatSymbols( decFS );
BigDecimal number = new BigDecimal(1000);
String result = dec.format(number);
I want to get "1000" as string with no other characters. Please help
note(react to post): I want to formate the number only, without grouping.
Simply:
DecimalFormat dec = new DecimalFormat();
dec.setGroupingUsed(false);
If you dont want any formatting marks in the number you should just call toString on the BigDecimal Object.
import java.math.*;
public class TestBigDecimal
{
public static void main(String[] args)
{
BigDecimal number = new BigDecimal(1000);
String result = number.toString();
}
}
String result = String.valueOf(number);
returns your number as a string with no formatting.