दशमलव विभाजक के रूप में अल्पविराम के साथ पार्स-डबल करने का सबसे अच्छा तरीका?


148

निम्नलिखित में परिणाम है Exception:

String p="1,234";
Double d=Double.valueOf(p); 
System.out.println(d);

वहाँ एक बेहतर तरीका है से पार्स "1,234"करने के लिए 1.234है p = p.replaceAll(",",".");:?


17
मेरे अनुभव में, ReplaceAll (), जैसा कि आपने सुझाव दिया है, ऐसा करने का सबसे अच्छा तरीका है। यह वर्तमान स्थान पर निर्भर नहीं करता है, यह सरल है, और यह काम करता है।
जूनस पुलका

1
@ मार्को अल्टिएरी: replaceAll(",",".")सभी कॉमा को डॉट्स से बदल देता है। अगर कोई अल्पविराम नहीं है, तो यह कुछ भी नहीं करता है। Double.valueOf()कार्य (केवल) स्ट्रिंग के साथ जो दशमलव विभाजक के रूप में डॉट का उपयोग करता है। यहां कुछ भी वर्तमान डिफ़ॉल्ट लोकेल से प्रभावित नहीं है। docs.oracle.com/javase/8/docs/api/java/lang/...
Joonas Pulakka

4
केवल समस्या replaceAll(",",".")यह है कि यह केवल तभी काम करेगा जब कोई अल्पविराम हो: यानी: 1,234,567 फेंक देगा java.lang.NumberFormatException: multiple points। सकारात्मक अग्रदर्शी के साथ एक regex पर्याप्त होगा p.replaceAll(",(?=[0-9]+,)", "").replaceAll(",", ".")पर अधिक: regular-expressions.info/lookaround.html
artemisian

2
कोई बात नहीं है। NumberFormatException अच्छी है। आप कैसे जान सकते हैं कि कौन सा अल्पविराम सही है? प्रारूप गलत है और आप जो कुछ भी कर सकते हैं वह उपयोगकर्ता के अपवाद से बेहतर पठनीय संदेश दिखा सकता है।
11 जनवरी को अविश्वसनीय जन

2
@ TheincredibleJan नहीं, प्रारूप गलत नहीं है। कुछ स्थान कॉमा को हजारों विभाजक के रूप में उपयोग करते हैं, इसलिए आप उनमें से एक से अधिक संख्या में हो सकते हैं और यह तकनीकी रूप से अभी भी एक वैध इनपुट है।
व्रतिस्लाव जिंद्रा

जवाबों:


206

Java.text.NumberFormat का उपयोग करें :

NumberFormat format = NumberFormat.getInstance(Locale.FRANCE);
Number number = format.parse("1,234");
double d = number.doubleValue();

11
यह केवल तभी काम करता है जब वर्तमान डिफ़ॉल्ट लोकेल एक दशमलव विभाजक के रूप में अल्पविराम का उपयोग करने के लिए होता है।
जूनास पुलका

6
चीजों को और गड़बड़ करने के लिए, कुछ स्थान हजारों विभाजक के रूप में अल्पविराम का उपयोग करते हैं , जिस स्थिति में "1,234" एक त्रुटि को फेंकने के बजाय 1234.0 के बराबर होगा।
जूनास पुलका

17
NumberFormat के साथ समस्या यह है कि यह चुपचाप अमान्य वर्णों को अनदेखा कर देगा। इसलिए यदि आप "1,23abc" को पार्स करने की कोशिश करते हैं, तो यह आपको बिना इंगित किए खुशी से 1.23 लौटाएगा कि पारित-किए गए स्ट्रिंग में गैर-पार्शियल अक्षर हैं। कुछ स्थितियों में जो वास्तव में वांछनीय हो सकती हैं, लेकिन मुझे नहीं लगता कि यह आमतौर पर वांछित व्यवहार है।
ई-रिज़

7
तुर्की के लिए, आपको नंबरफ़ॉर्मैट.गेटइन्स्टेंस (नया लोकेल (tr_TR)) का उपयोग करना चाहिए
गुने गुल्लेकिन


67

आप इसका उपयोग कर सकते हैं (फ्रेंच ,विभाजक दशमलव विभाजक के लिए है)

NumberFormat nf = NumberFormat.getInstance(Locale.FRANCE);
nf.parse(p);

या आप java.text.DecimalFormatउचित प्रतीकों का उपयोग और सेट कर सकते हैं :

DecimalFormat df = new DecimalFormat();
DecimalFormatSymbols symbols = new DecimalFormatSymbols();
symbols.setDecimalSeparator(',');
symbols.setGroupingSeparator(' ');
df.setDecimalFormatSymbols(symbols);
df.parse(p);

हां ... अगर हम हजार ग्रुपिंग सेपरेटर सेट नहीं करते हैं और सिर्फ फ्रेंच फॉर्मेट का इस्तेमाल करते हैं, तो स्पेनिश फॉर्मेट (1.222.222,33) में एक नंबर "1 222 222,33" में बदल जाएगा, जो कि मुझे नहीं चाहिए । तो धन्यवाद!
पश्चिमीगंज

1
एक और बात, स्पेनिश स्थान के रूप में "default` सूचीबद्ध है नहीं है और मैं एक का निर्माण नहीं कर सकते हैं Localeके साथ सही प्रारूप के साथ new Locale("es", "ES")और फिर स्वचालित रूप से संख्या स्ट्रिंग पार्स NumberFormatसाथ, ,दशमलव के रूप में विभाजक और .हजार समूह विभाजक के रूप में केवल। DecimalFormatकाम करता है।
WesternGun

सभी देश वहां उपलब्ध क्यों नहीं हैं? पोलिश नंबरों को प्रारूपित करने के लिए फ्रांसीसी लोकेल का उपयोग करने के बारे में मुझे अजीब लगता है ...
लाइन

18

जैसा कि E-Riz बताते हैं, NumberFormat.parse (स्ट्रिंग) पार्स "1,23abc" को 1.23 के रूप में। पूरा इनपुट लेने के लिए हम उपयोग कर सकते हैं:

public double parseDecimal(String input) throws ParseException{
  NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.getDefault());
  ParsePosition parsePosition = new ParsePosition(0);
  Number number = numberFormat.parse(input, parsePosition);

  if(parsePosition.getIndex() != input.length()){
    throw new ParseException("Invalid input", parsePosition.getIndex());
  }

  return number.doubleValue();
}

2
: इस रणनीति विस्तार यहाँ से समझाया गया है ibm.com/developerworks/library/j-numberformat
जानूस Varmarken

7
Double.parseDouble(p.replace(',','.'))

... यह बहुत जल्दी है क्योंकि यह एक चार-चार आधार पर अंतर्निहित चरित्र सरणी की खोज करता है। स्ट्रिंग की जगह संस्करण मूल्यांकन करने के लिए एक RegEx संकलित करते हैं।

मूल रूप से प्रतिस्थापित (चार, चार) लगभग 10 गुना तेज है और चूंकि आप निम्न-स्तरीय कोड में इस तरह की चीजें कर रहे हैं, इसलिए इस बारे में सोचने के लिए समझ में आता है। हॉट स्पॉट ऑप्टिमाइज़र इसका पता नहीं लगाएगा ... निश्चित रूप से मेरे सिस्टम पर नहीं है।


4

यदि आपको सही लोकेल का पता नहीं है और स्ट्रिंग में एक हजार विभाजक हो सकते हैं तो यह अंतिम उपाय हो सकता है:

    doubleStrIn = doubleStrIn.replaceAll("[^\\d,\\.]++", "");
    if (doubleStrIn.matches(".+\\.\\d+,\\d+$"))
        return Double.parseDouble(doubleStrIn.replaceAll("\\.", "").replaceAll(",", "."));
    if (doubleStrIn.matches(".+,\\d+\\.\\d+$"))
        return Double.parseDouble(doubleStrIn.replaceAll(",", ""));
    return Double.parseDouble(doubleStrIn.replaceAll(",", "."));

ध्यान रखें: यह खुशी से "R 1 52.43,2" जैसे "15243.2" के तार को पार्स करेगा।


4

यह मेरे अपने कोड में उपयोग की जाने वाली स्थिर विधि है:

public static double sGetDecimalStringAnyLocaleAsDouble (String value) {

    if (value == null) {
        Log.e("CORE", "Null value!");
        return 0.0;
    }

    Locale theLocale = Locale.getDefault();
    NumberFormat numberFormat = DecimalFormat.getInstance(theLocale);
    Number theNumber;
    try {
        theNumber = numberFormat.parse(value);
        return theNumber.doubleValue();
    } catch (ParseException e) {
        // The string value might be either 99.99 or 99,99, depending on Locale.
        // We can deal with this safely, by forcing to be a point for the decimal separator, and then using Double.valueOf ...
        //http://stackoverflow.com/questions/4323599/best-way-to-parsedouble-with-comma-as-decimal-separator
        String valueWithDot = value.replaceAll(",",".");

        try {
          return Double.valueOf(valueWithDot);
        } catch (NumberFormatException e2)  {
            // This happens if we're trying (say) to parse a string that isn't a number, as though it were a number!
            // If this happens, it should only be due to application logic problems.
            // In this case, the safest thing to do is return 0, having first fired-off a log warning.
            Log.w("CORE", "Warning: Value is not a number" + value);
            return 0.0;
        }
    }
}

5
क्या होगा यदि डिफ़ॉल्ट लोकेल जर्मन जैसा कुछ है, जहां एक अल्पविराम दशमलव स्थान को दर्शाता है? आप उदाहरण के लिए, "1,000,000" में उत्तीर्ण हो सकते हैं, जो जर्मन लोकेल में पार्स नहीं होगा और फिर "1.000.000" द्वारा प्रतिस्थापित किया जाएगा जो कि एक वैध डबल नहीं है।
एडी कर्टिस

हाय @jimycar, मैंने अभी अपने स्थैतिक विधि के वर्तमान संस्करण का उपयोग करने के लिए अपना उत्तर अपडेट किया है। मुझे आशा है कि यह आपकी समस्या का हल करेगा! पीट
पीट

1

आप निश्चित रूप से सही स्थान का उपयोग करने की आवश्यकता है। यह सवाल मदद करेगा।


0

उस स्थिति में जहां आपको प्राप्त स्ट्रिंग मान का लोकेल नहीं पता है और यह जरूरी नहीं है कि वर्तमान डिफ़ॉल्ट लोकेल के समान ही आप इसका उपयोग कर सकते हैं:

private static double parseDouble(String price){
    String parsedStringDouble;
    if (price.contains(",") && price.contains(".")){
        int indexOfComma = price.indexOf(",");
        int indexOfDot = price.indexOf(".");
        String beforeDigitSeparator;
        String afterDigitSeparator;
        if (indexOfComma < indexOfDot){
            String[] splittedNumber = price.split("\\.");
            beforeDigitSeparator = splittedNumber[0];
            afterDigitSeparator = splittedNumber[1];
        }
        else {
            String[] splittedNumber = price.split(",");
            beforeDigitSeparator = splittedNumber[0];
            afterDigitSeparator = splittedNumber[1];
        }
        beforeDigitSeparator = beforeDigitSeparator.replace(",", "").replace(".", "");
        parsedStringDouble = beforeDigitSeparator+"."+afterDigitSeparator;
    }
    else {
        parsedStringDouble = price.replace(",", "");
    }

    return Double.parseDouble(parsedStringDouble);

}

यह एक डबल कोई बात नहीं लौटेगा कि स्ट्रिंग का स्थान क्या है। और चाहे कितने भी कॉमा या प्वाइंट हों। तो पासिंग 1,000,000.54काम करेगा 1.000.000,54इसलिए आपको स्ट्रिंग को पार्स करने के लिए डिफ़ॉल्ट लोकेल पर निर्भर नहीं रहना पड़ेगा। कोड उतना अनुकूलित नहीं है क्योंकि यह किसी भी सुझाव का स्वागत है। मैंने यह सुनिश्चित करने के लिए अधिकांश मामलों का परीक्षण करने की कोशिश की कि यह समस्या हल करता है लेकिन मुझे यकीन नहीं है कि यह सभी को कवर करता है। यदि आपको कोई मान मिल रहा है तो मुझे बताएं।


-5

यह काम करेगा:

Double.parseDouble(p.replace(',','.')); 

6
प्रारंभिक प्रश्न में कहा गया कि "1.234 पाने के लिए" 1,234 "को पार्स करने का एक बेहतर तरीका है: p = p.replaceAll (", "," ";"); ", अगर आपको लगता हैreplace उपयोग करने से काफी भिन्नता है replaceAll, तो कृपया बताएं कि क्यों।
SuperBiasedMan
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.