简体   繁体   English

如何通过使用DecimalFormat将代表百分比,货币的数字值转换为字符串并返回BigDecimal

[英]How to convert number value representing eg percents, currency to string and back to BigDecimal by using DecimalFormat

Hi I'd like know how to format BigDecimal representing numbers,percents,moneys,integers to String in Locales and from String back to BigDecimal. 嗨,我想知道如何格式化表示数字,百分比,货币,整数的BigDecimal到语言环境中的String,以及从String转换回BigDecimal的格式。 I'm using DecimalFormat which is powerful, but I'm not sure how to use conversion to exact type in default user locales. 我正在使用功能强大的DecimalFormat,但是我不确定如何在默认用户区域设置中使用转换为确切类型。 I first time use this: 我第一次使用这个:

DecimalFormat.getCurrencyInstance().format( obj );
DecimalFormat.getCurrencyInstance().parse( source );

But with large numbers its misrepresents their value. 但是大量使用它却无法代表其价值。 So i find something and get this: 所以我找到了一些东西,得到了这个:

DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setParseBigDecimal( true );
BigDecimal bd = ( BigDecimal ) decimalFormat.parse( value );

But how to combine these thinks. 但是如何结合这些想法。 I probably need set to DecimalFormat some pattern which is used in NumberFormat.get???instance(), but I don't know how and if isn't get some strange behavior. 我可能需要将NumberFormat.get ??? instance()中使用的某种模式设置为DecimalFormat,但是我不知道如何以及是否不会得到一些奇怪的行为。

So Please someone who has experience with this can you help me? 所以,请有经验的人可以帮我吗? Thanks Pavel 谢谢帕维尔

I think your best bet is to assume that getCurrencyInstace() returns a DecimalFormat , which it probably does in all of the "important" locales. 我认为您最好的选择是假设getCurrencyInstace()返回一个DecimalFormat ,它可能在所有“重要”语言环境中都这样做。 To be safe you could employ instanceof : 为了安全起见,您可以使用instanceof

public static BigDecimal parseCurrencyPrecise (String value)
{
    NumberFormat  format = NumberFormat.getCurrencyInstance ();
    if (format instanceof DecimalFormat)
        ((DecimalFormat) format).setParseBigDecimal (true);

    Number  result = format.parse (value);
    if (result instanceof BigDecimal)
        return (BigDecimal) result;
    else {
        // Oh well...
        return new BigDecimal (result.doubleValue ());
    }
}

In our application we basically do the same for something different where you'd need SimpleDateFormat , but only have DateFormat in general case. 在我们的应用程序中,对于需要SimpleDateFormat其他地方,我们基本上会执行相同的操作,但通常情况下只有DateFormat

After a while a write this. 过了一会儿写这个。 It's seems to be working, but I'm not sure if it will work correctly on all Times. 它似乎正在运行,但是我不确定它是否在所有时代都能正常运行。 Maybe it helps someone else. 也许它可以帮助别人。 I also hope that it does not violate any license). 我也希望它不违反任何许可)。

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.ParseException;
import java.util.Currency;
import java.util.Locale;

import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.util.UResourceBundle;

public class NumericHelper {

    public static BigDecimal parseStringToBigDecimal( String value, DecimalFormat decimalFormat ) throws ParseException {
        decimalFormat.setParseBigDecimal( true );
        return ( BigDecimal ) decimalFormat.parse( value );
    }

    /**
     * Extracted code from {@link NumberFormat#getPattern()} and
     * {@link java.text.NumberFormat#getInstance(Locale desiredLocale, int choice)} with some
     * modifications to get DecimalFormat with good Pattern
     * 
     * @param choice is static values from class {@link NumberFormat} eg
     *            {@link NumberFormat#INTEGERSTYLE}
     */
    public static DecimalFormat getDecimalFormatWithPattern( Locale desiredLocale, int choice ) {
        ICUResourceBundle rb = ( ICUResourceBundle ) UResourceBundle.getBundleInstance( ICUResourceBundle.ICU_BASE_NAME, desiredLocale );
        String[] numberPatterns = rb.getStringArray( "NumberPatterns" );

        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance( desiredLocale );
        int entry = ( choice == NumberFormat.INTEGERSTYLE ) ? NumberFormat.NUMBERSTYLE : choice;
        DecimalFormat format = new DecimalFormat( numberPatterns[entry], symbols );

        if ( choice == NumberFormat.INTEGERSTYLE ) {
            format.setMaximumFractionDigits( 0 );
            format.setDecimalSeparatorAlwaysShown( false );
            format.setParseIntegerOnly( true );
        }
        else if ( choice == NumberFormat.CURRENCYSTYLE ) {
            adjustForCurrencyDefaultFractionDigits( format );
        }

        return format;
    }

    /**
     * Extracted from {@link DecimalFormat#adjustForCurrencyDefaultFractionDigits()} because it can
     * not be called
     */
    protected static void adjustForCurrencyDefaultFractionDigits( DecimalFormat decimalFormat ) {
        DecimalFormatSymbols symbols = decimalFormat.getDecimalFormatSymbols();

        Currency currency = symbols.getCurrency();
        if ( currency == null ) {
            try {
                currency = Currency.getInstance( symbols.getInternationalCurrencySymbol() );
            }
            catch ( IllegalArgumentException e ) {
            }
        }
        if ( currency != null ) {
            int digits = currency.getDefaultFractionDigits();
            if ( digits != -1 ) {
                int oldMinDigits = decimalFormat.getMinimumFractionDigits();
                // Common patterns are "#.##", "#.00", "#".
                // Try to adjust all of them in a reasonable way.
                if ( oldMinDigits == decimalFormat.getMaximumFractionDigits() ) {
                    decimalFormat.setMinimumFractionDigits( digits );
                    decimalFormat.setMaximumFractionDigits( digits );
                }
                else {
                    decimalFormat.setMinimumFractionDigits( Math.min( digits, oldMinDigits ) );
                    decimalFormat.setMaximumFractionDigits( digits );
                }
            }
        }
    }
}

After a next other time I figured that NumberFormat.get***Instance() methods it returns its descendant classes ( DecimalFormat ). 再下一次,我发现NumberFormat.get *** Instance()方法将返回其后代类( DecimalFormat )。 I'm not sure how this can work, but it works. 我不确定这如何工作,但可以。 In the code is moment, that trying to get format from LocaleServiceProviderPool so I believe that it also returns DecimalFormat, if it does, thats no problem use this original methods and cast to DecimalFormat but if doesnt, you must check it . 在代码中,是试图从LocaleServiceProviderPool获取格式的代码,所以我相信它还会返回DecimalFormat,如果确实如此,则使用此原始方法并转换为DecimalFormat没问题,但如果没有,则必须检查它 In code what I write is this part omitted 在代码中我写的是这部分被省略

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM