BigDecimal रूपांतरण के लिए सुरक्षित स्ट्रिंग


120

मैं स्ट्रिंग से कुछ BigDecimal मान पढ़ने की कोशिश कर रहा हूं। मान लें कि मेरे पास यह स्ट्रिंग है: "1,000,000,000.99999999999999999" और मैं इसके लिए एक बिगडेसिमल प्राप्त करना चाहता हूं। इसे करने का तरीका क्या है?

सबसे पहले, मैं स्ट्रिंग की जगह (अल्पविराम आदि की जगह) का उपयोग कर समाधान पसंद नहीं करता। मुझे लगता है कि मेरे लिए उस काम को करने के लिए कुछ साफ सुथरे फॉर्मेटर होने चाहिए।

मुझे डेसीमलफार्मेटर वर्ग मिला है, हालांकि यह दोगुनी मात्रा में संचालित होता है - बड़ी मात्रा में परिशुद्धता खो जाती है।

तो, मैं इसे कैसे कर सकता हूं?


क्योंकि कुछ कस्टम प्रारूप दिए गए हैं, इसलिए यह आपके प्रारूप को BigDecimal- संगत प्रारूप में परिवर्तित करने के लिए एक दर्द है।
14

2
"क्योंकि कुछ कस्टम प्रारूप दिया गया है यह एक दर्द है ..." मुझे पता नहीं, यह समस्या डोमेन को अलग करता है। पहले आप मानव-पठनीय सामान को स्ट्रिंग से बाहर साफ करते हैं, फिर कुछ ऐसी चीज़ों को सौंपते हैं जो जानता है कि कैसे सही ढंग से और कुशलता से परिणाम को चालू करें BigDecimal
टीजे क्राउडर

जवाबों:


90

की जाँच करें setParseBigDecimalDecimalFormat में। इस सेटर के साथ, parseआपके लिए एक BigDecimal लौटाएगा।


1
BigDecimal वर्ग में कंस्ट्रक्टर कस्टम प्रारूपों का समर्थन नहीं करता है। प्रश्न में मैंने जो उदाहरण दिया है वह कस्टम प्रारूप (कॉमा) का उपयोग करता है। आप इसका निर्माण करने वाले का उपयोग करके BigDecimal को पार्स नहीं कर सकते।
बेगमक्स

24
यदि आप अपना उत्तर पूरी तरह से बदलने जा रहे हैं , तो मैं उत्तर में इसका उल्लेख करने का सुझाव दूंगा। यह बहुत अजीब लगता है जब लोगों ने बताया कि आपके मूल उत्तर का कोई मतलब नहीं था। :-)
टीजे क्राउडर

1
हाँ, उस विधि पर ध्यान नहीं दिया। धन्यवाद, ऐसा करने का सबसे अच्छा तरीका लगता है। अब यह परीक्षण करें और अगर यह ठीक से काम करता है - जवाब स्वीकार करें।
बेगमक्स

15
क्या आप एक उदाहरण प्रदान कर सकते हैं?
जे वुडचुक

61
String value = "1,000,000,000.999999999999999";
BigDecimal money = new BigDecimal(value.replaceAll(",", ""));
System.out.println(money);

पूर्ण कोड यह साबित करने के लिए कि कोई NumberFormatExceptionफेंका नहीं गया है:

import java.math.BigDecimal;

public class Tester {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String value = "1,000,000,000.999999999999999";
        BigDecimal money = new BigDecimal(value.replaceAll(",", ""));
        System.out.println(money);
    }
}

उत्पादन

1000000000.999999999999999


@ स्तेव मैकलियोड .... नहीं, मैंने अभी इसका परीक्षण किया है .... मेरा मूल्य है1000000000.999999999999999
बुआके सिंडी

10
जर्मन लोकेल के साथ प्रयास करें, और 1.000.000.000,999999999999
टोफूबीर

@ # टोफूबीर .... उदाहरण 1,000,000,000.99999999999999999 था। अगर मुझे आपका लोकेल करना होता है, तो मुझे सभी डॉट्स को स्पेस में बदलना होगा ....
बुहाके सिंडी

14
तो, यह सुरक्षित नहीं है। आप सभी स्थानों को नहीं जानते हैं।
यमजोरोस

3
यह ठीक है अगर आप सिर्फ DecimalFormatSymbols.getInstance().getGroupingSeparator()कॉमा के बजाय उदाहरण के लिए उपयोग करते हैं, तो अलग-अलग स्थानों के बारे में ध्यान देने की आवश्यकता नहीं है।
जेसन सी

22

निम्न नमूना कोड अच्छी तरह से काम करता है (स्थानीय रूप से गतिशील रूप से प्राप्त करने की आवश्यकता है)

import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.DecimalFormat;
import java.text.ParsePosition;
import java.util.Locale;

class TestBigDecimal {
    public static void main(String[] args) {

        String str = "0,00";
        Locale in_ID = new Locale("in","ID");
        //Locale in_ID = new Locale("en","US");

        DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance(in_ID);
        nf.setParseBigDecimal(true);

        BigDecimal bd = (BigDecimal)nf.parse(str, new ParsePosition(0));

        System.out.println("bd value : " + bd);
    }
}

6

कोड क्लीनर हो सकता है, लेकिन यह विभिन्न स्थानों के लिए चाल करने के लिए लगता है।

import java.math.BigDecimal;
import java.text.DecimalFormatSymbols;
import java.util.Locale;


public class Main
{
    public static void main(String[] args)
    {
        final BigDecimal numberA;
        final BigDecimal numberB;

        numberA = stringToBigDecimal("1,000,000,000.999999999999999", Locale.CANADA);
        numberB = stringToBigDecimal("1.000.000.000,999999999999999", Locale.GERMANY);
        System.out.println(numberA);
        System.out.println(numberB);
    }

    private static BigDecimal stringToBigDecimal(final String formattedString,
                                                 final Locale locale)
    {
        final DecimalFormatSymbols symbols;
        final char                 groupSeparatorChar;
        final String               groupSeparator;
        final char                 decimalSeparatorChar;
        final String               decimalSeparator;
        String                     fixedString;
        final BigDecimal           number;

        symbols              = new DecimalFormatSymbols(locale);
        groupSeparatorChar   = symbols.getGroupingSeparator();
        decimalSeparatorChar = symbols.getDecimalSeparator();

        if(groupSeparatorChar == '.')
        {
            groupSeparator = "\\" + groupSeparatorChar;
        }
        else
        {
            groupSeparator = Character.toString(groupSeparatorChar);
        }

        if(decimalSeparatorChar == '.')
        {
            decimalSeparator = "\\" + decimalSeparatorChar;
        }
        else
        {
            decimalSeparator = Character.toString(decimalSeparatorChar);
        }

        fixedString = formattedString.replaceAll(groupSeparator , "");
        fixedString = fixedString.replaceAll(decimalSeparator , ".");
        number      = new BigDecimal(fixedString);

        return (number);
    }
}

3

यहाँ है कि मैं यह कैसे करेंगे:

public String cleanDecimalString(String input, boolean americanFormat) {
    if (americanFormat)
        return input.replaceAll(",", "");
    else
        return input.replaceAll(".", "");
}

जाहिर है, अगर यह उत्पादन कोड में जा रहे थे, तो यह इतना आसान नहीं होगा।

मैं स्ट्रिंग से कॉमा को हटाने के साथ कोई समस्या नहीं देखता।


और अगर स्ट्रिंग अमेरिकी प्रारूप में नहीं है? जर्मनी में, यह 1.000.000.000,999999999999999 होगा
स्टीव मैकलियोड

1
यहां मुख्य समस्या यह है कि संख्याओं को अलग-अलग स्रोतों से प्राप्त किया जा सकता है, जिनमें से प्रत्येक का अपना प्रारूप होता है। तो इस स्थिति में इसे करने का सबसे अच्छा तरीका प्रत्येक स्रोतों के लिए कुछ "संख्या प्रारूप" को परिभाषित करना होगा। मैं सरल प्रतिकृति के साथ ऐसा नहीं कर सकता क्योंकि एक स्रोत में "123 456 789" प्रारूप हो सकता है और दूसरा "123.456.789"।
bezmax 14

मैं देख रहा हूँ कि आप चुपचाप "एक पंक्ति विधि" शब्द को पुनर्परिभाषित कर रहे हैं ... ;-)
सेर टॉरोक

@Steve: यह एक बहुत ही बुनियादी अंतर है जो स्पष्ट रूप से निपटने के लिए कहता है, न कि "regexp सभी फिट बैठता है" दृष्टिकोण।
माइकल बोरगवर्ड

2
@ मोम: "यहां मुख्य समस्या यह है कि संख्याओं को अलग-अलग स्रोतों से प्राप्त किया जा सकता है, जिनमें से प्रत्येक का अपना प्रारूप है।" आपके द्वारा नियंत्रित न होने वाले कोड को सौंपने से पहले इनपुट को साफ करने के बजाय, जो आपके तर्क के लिए तर्क देता है ।
टीजे क्राउडर

3

मुझे लोकल को जाने-पहचाने और लोकल-इंडिपेंडेंट होने के बिना एक स्ट्रिंग को बिगडेसिमल में बदलने के लिए एक समाधान की आवश्यकता थी। मुझे इस समस्या के लिए कोई मानक समाधान नहीं मिला, इसलिए मैंने अपनी सहायक विधि लिखी। हो सकता है कि यह किसी और की भी मदद करे:

अद्यतन: चेतावनी! यह सहायक विधि केवल दशमलव संख्याओं के लिए काम करती है, इसलिए संख्याएँ जिनमें हमेशा दशमलव बिंदु होता है! अन्यथा हेल्पर विधि 1000 और 999999 (प्लस / माइनस) के बीच की संख्या के लिए एक गलत परिणाम दे सकती है। उसके महान इनपुट के लिए bezmax के लिए धन्यवाद!

static final String EMPTY = "";
static final String POINT = '.';
static final String COMMA = ',';
static final String POINT_AS_STRING = ".";
static final String COMMA_AS_STRING = ",";

/**
     * Converts a String to a BigDecimal.
     *     if there is more than 1 '.', the points are interpreted as thousand-separator and will be removed for conversion
     *     if there is more than 1 ',', the commas are interpreted as thousand-separator and will be removed for conversion
     *  the last '.' or ',' will be interpreted as the separator for the decimal places
     *  () or - in front or in the end will be interpreted as negative number
     *
     * @param value
     * @return The BigDecimal expression of the given string
     */
    public static BigDecimal toBigDecimal(final String value) {
        if (value != null){
            boolean negativeNumber = false;

            if (value.containts("(") && value.contains(")"))
               negativeNumber = true;
            if (value.endsWith("-") || value.startsWith("-"))
               negativeNumber = true;

            String parsedValue = value.replaceAll("[^0-9\\,\\.]", EMPTY);

            if (negativeNumber)
               parsedValue = "-" + parsedValue;

            int lastPointPosition = parsedValue.lastIndexOf(POINT);
            int lastCommaPosition = parsedValue.lastIndexOf(COMMA);

            //handle '1423' case, just a simple number
            if (lastPointPosition == -1 && lastCommaPosition == -1)
                return new BigDecimal(parsedValue);
            //handle '45.3' and '4.550.000' case, only points are in the given String
            if (lastPointPosition > -1 && lastCommaPosition == -1){
                int firstPointPosition = parsedValue.indexOf(POINT);
                if (firstPointPosition != lastPointPosition)
                    return new BigDecimal(parsedValue.replace(POINT_AS_STRING, EMPTY));
                else
                    return new BigDecimal(parsedValue);
            }
            //handle '45,3' and '4,550,000' case, only commas are in the given String
            if (lastPointPosition == -1 && lastCommaPosition > -1){
                int firstCommaPosition = parsedValue.indexOf(COMMA);
                if (firstCommaPosition != lastCommaPosition)
                    return new BigDecimal(parsedValue.replace(COMMA_AS_STRING, EMPTY));
                else
                    return new BigDecimal(parsedValue.replace(COMMA, POINT));
            }
            //handle '2.345,04' case, points are in front of commas
            if (lastPointPosition < lastCommaPosition){
                parsedValue = parsedValue.replace(POINT_AS_STRING, EMPTY);
                return new BigDecimal(parsedValue.replace(COMMA, POINT));
            }
            //handle '2,345.04' case, commas are in front of points
            if (lastCommaPosition < lastPointPosition){
                parsedValue = parsedValue.replace(COMMA_AS_STRING, EMPTY);
                return new BigDecimal(parsedValue);
            }
            throw new NumberFormatException("Unexpected number format. Cannot convert '" + value + "' to BigDecimal.");
        }
        return null;
    }

बेशक मैंने विधि का परीक्षण किया है:

@Test(dataProvider = "testBigDecimals")
    public void toBigDecimal_defaultLocaleTest(String stringValue, BigDecimal bigDecimalValue){
        BigDecimal convertedBigDecimal = DecimalHelper.toBigDecimal(stringValue);
        Assert.assertEquals(convertedBigDecimal, bigDecimalValue);
    }
    @DataProvider(name = "testBigDecimals")
    public static Object[][] bigDecimalConvertionTestValues() {
        return new Object[][] {
                {"5", new BigDecimal(5)},
                {"5,3", new BigDecimal("5.3")},
                {"5.3", new BigDecimal("5.3")},
                {"5.000,3", new BigDecimal("5000.3")},
                {"5.000.000,3", new BigDecimal("5000000.3")},
                {"5.000.000", new BigDecimal("5000000")},
                {"5,000.3", new BigDecimal("5000.3")},
                {"5,000,000.3", new BigDecimal("5000000.3")},
                {"5,000,000", new BigDecimal("5000000")},
                {"+5", new BigDecimal("5")},
                {"+5,3", new BigDecimal("5.3")},
                {"+5.3", new BigDecimal("5.3")},
                {"+5.000,3", new BigDecimal("5000.3")},
                {"+5.000.000,3", new BigDecimal("5000000.3")},
                {"+5.000.000", new BigDecimal("5000000")},
                {"+5,000.3", new BigDecimal("5000.3")},
                {"+5,000,000.3", new BigDecimal("5000000.3")},
                {"+5,000,000", new BigDecimal("5000000")},
                {"-5", new BigDecimal("-5")},
                {"-5,3", new BigDecimal("-5.3")},
                {"-5.3", new BigDecimal("-5.3")},
                {"-5.000,3", new BigDecimal("-5000.3")},
                {"-5.000.000,3", new BigDecimal("-5000000.3")},
                {"-5.000.000", new BigDecimal("-5000000")},
                {"-5,000.3", new BigDecimal("-5000.3")},
                {"-5,000,000.3", new BigDecimal("-5000000.3")},
                {"-5,000,000", new BigDecimal("-5000000")},
                {null, null}
        };
    }

1
क्षमा करें, लेकिन मैं यह नहीं देखता कि किनारे-मामलों के कारण यह कैसे उपयोगी हो सकता है। उदाहरण के लिए, आप कैसे जानते हैं कि क्या 7,333प्रतिनिधित्व करता है ? क्या यह 7333 या 7 और 1/3 (7.333) है? विभिन्न स्थानों में उस संख्या को अलग तरीके से पार्स किया जाएगा। यहाँ अवधारणा का सबूत है: ideone.com/Ue9rT8
bezmax

अच्छा इनपुट, व्यवहार में यह समस्या कभी नहीं थी। मैं अपनी पोस्ट को अपडेट करूंगा, बहुत-बहुत धन्यवाद! और मैं इन लोकेल विशेषों के लिए परीक्षण में सुधार करूंगा ताकि यह पता चल सके कि परेशानी कहां से आएगी।
user3227576

1
मैंने अलग-अलग लोकल और अलग-अलग नंबरों के समाधान की जाँच की है ... और हम सभी के लिए काम करता है, क्योंकि हमारे पास हमेशा एक दशमलव बिंदु के साथ संख्याएँ होती हैं (हम एक टेक्स्टफाइल से मनी-वैल्यू पढ़ रहे हैं)। मैंने उत्तर के लिए एक चेतावनी जोड़ी है।
user3227576

2
resultString = subjectString.replaceAll("[^.\\d]", "");

आपके स्ट्रिंग से अंकों और डॉट को छोड़कर सभी वर्णों को हटा देगा।

यह स्थान-जागरूक बनाने के लिए, आप उपयोग कर सकते हैं getDecimalSeparator()से java.text.DecimalFormatSymbols। मैं जावा नहीं जानता, लेकिन यह इस तरह दिख सकता है:

sep = getDecimalSeparator()
resultString = subjectString.replaceAll("[^"+sep+"\\d]", "");

जो गैर-अमेरिकी संख्या के लिए अप्रत्याशित परिणाम देगा - जस्टिन के जवाब के लिए टिप्पणियां देखें।
Péter Török

2

पुराना विषय है, लेकिन शायद सबसे आसान अपाचे कॉमन्स नंबर यूटिल्स का उपयोग करना है जिसमें एक विधि createBigDecimal (स्थिर मूल्य) है ...।

मुझे लगता है (आशा) यह स्थानों को ध्यान में रखता है अन्यथा यह बेकार होगा।


createBigDecimal केवल नए BigDecimal (string) के लिए एक रैपर है, जैसा कि नंबरयूलेट्स सोर्स कोड में कहा गया है, जो कोई लोकेल AFAIK नहीं मानता है
Mar Bar

1

कृपया मेरे लिए इसके काम करने का प्रयास करें

BigDecimal bd ;
String value = "2000.00";

bd = new BigDecimal(value);
BigDecimal currency = bd;

2
यह तरीका दशमलव बिंदु और थूथन समूह के लिए कस्टम सीमांकक निर्दिष्ट करने का समर्थन नहीं करता है।
बेज़मैक्स

हां, लेकिन यह हैशपॉइंट जैसी ऑब्जेक्ट से स्ट्रिंग बिगडिमल मान प्राप्त करने और अन्य सेवाओं को कॉल करने के लिए बिगडेसिमल मान में संग्रहीत करने के लिए है
राजकुमार टेकक्राफ्ट

1
हां, लेकिन यह सवाल नहीं था।
bezmax

मेरे लिए भी काम करता है
सप्तेश
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.