নিরাপদ স্ট্রিং থেকে বিগডিসিমাল রূপান্তর


120

আমি স্ট্রিং থেকে কিছু বিগডিসিমাল মান পড়ার চেষ্টা করছি। ধরা যাক আমার কাছে এই স্ট্রিং রয়েছে: "1,000,000,000.999999999999999" এবং আমি এটি থেকে একটি বিগডিসিমাল পেতে চাই। এটি করার উপায় কী?

প্রথমত, আমি স্ট্রিং প্রতিস্থাপন (কমাগুলি প্রতিস্থাপন করা) ব্যবহার করে সমাধানগুলি পছন্দ করি না। আমার মনে হয় আমার পক্ষে এই কাজটি করার জন্য কিছু ঝরঝরে ফর্ম্যাটর থাকা উচিত।

আমি একটি ডেসিমালফর্মেটর ক্লাস পেয়েছি, যদিও এটি দ্বিগুণ মাধ্যমে কাজ করে - বিশাল পরিমাণ নির্ভুলতা হারিয়ে যায় are

তো, আমি কীভাবে এটি করতে পারি?


কিছু কাস্টম ফর্ম্যাট দেওয়ার কারণে এটি আপনার ফর্ম্যাটটিকে বিগডিসিমাল-সামঞ্জস্যপূর্ণ ফর্ম্যাটে রূপান্তর করতে ব্যথা হয়।
বেজম্যাক্স

2
"কারণ কিছু কাস্টম ফর্ম্যাট দেওয়া এটি একটি ব্যথা ..." আমি জানি না, এটি ধরণের সমস্যা ডোমেনকে আলাদা করে দেয়। প্রথমে আপনি মানব-পঠনযোগ্য স্ট্রিংটিকে স্ট্রিংয়ের বাইরে পরিষ্কার করুন, তারপরে এমন কোনও কিছুর হাতে তুলে দিন যা কীভাবে সঠিকভাবে এবং দক্ষতার সাথে ফলাফলকে একটিতে রূপান্তর করতে জানে BigDecimal
টিজে ক্রাউডার

উত্তর:


90

পরীক্ষা করে দেখুন setParseBigDecimalDecimalFormat হবে। এই parseসেটটার দিয়ে আপনার জন্য একটি বিগডিসিমাল ফিরিয়ে দেবে।


1
বিগডিসিমাল ক্লাসে কনস্ট্রাক্টর কাস্টম ফর্ম্যাটগুলিকে সমর্থন করে না। প্রশ্নটিতে আমি যে উদাহরণ দিয়েছি তা কাস্টম বিন্যাস (কমা) ব্যবহার করে। আপনি এটি নির্মাণকারীর ব্যবহার করে বিগডিসিমালে পার্স করতে পারবেন না।
বেজম্যাক্স

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.999999999999999। যদি আপনার লোকেলটি করতে হয় তবে আমাকে সমস্ত বিন্দু স্থানকে স্থানান্তর করতে হবে ....
বুহাকে সিন্ধি

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" থাকতে পারে বলে সাধারণ রিপ্ল্যাকিংয়ের সাহায্যে আমি এটি করতে পারি না।
বেজম্যাক্স

আমি দেখছি আপনি নিঃশব্দে "একটি লাইন পদ্ধতি" শব্দটির নতুন সংজ্ঞা দিচ্ছেন ... ;-)
পিটার টারিক

@ স্টিভ: এটি একটি দুর্দান্ত মৌলিক পার্থক্য যা সুস্পষ্ট হ্যান্ডলিংয়ের জন্য আহ্বান জানায়, "রেজিপ্সপ সব ফিট করে না" পদ্ধতির নয়।
মাইকেল বর্গওয়ার্ট

2
@ ম্যাক্স: "এখানে মূল সমস্যাটি হ'ল প্রত্যেকের নিজস্ব ফর্ম্যাট থাকায় বিভিন্ন উত্স থেকে সংখ্যাগুলি আনা যেত" কোনটি যুক্তি জন্য , বরং বিরুদ্ধে চেয়ে আপনার কোড আপনি নিয়ন্ত্রণ না বন্ধ হস্তান্তর সামনে ইনপুট পরিষ্কারের।
টিজে ক্রাউডার

3

লোকাল না জেনে এবং লোকেল-ইন্ডিপেন্ডেন্ট না হয়ে স্ট্রিংকে একটি বিগডিসিমালে রূপান্তর করার জন্য আমার একটি সমাধান দরকার needed আমি এই সমস্যার জন্য কোনও মানক সমাধান খুঁজে পাইনি তাই আমি আমার নিজের সহায়ক পদ্ধতিটি লিখেছি। এটি অন্য কাউকেও সহায়তা করতে পারে:

আপডেট: সতর্কতা! এই সহায়ক পদ্ধতিটি কেবলমাত্র দশমিক সংখ্যার জন্য কাজ করে, তাই যে সংখ্যাগুলিতে সর্বদা দশমিক পয়েন্ট থাকে! অন্যথায় সহায়ক পদ্ধতিটি 1000 এবং 999999 (প্লাস / বিয়োগ) এর মধ্যে সংখ্যার জন্য একটি ভুল ফলাফল সরবরাহ করতে পারে। তার দুর্দান্ত ইনপুটটির জন্য বেজম্যাক্সকে ধন্যবাদ!

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)? বিভিন্ন লোকেলে সেই সংখ্যাটি আলাদাভাবে পার্স করা হবে। এখানে ধারণার প্রমাণ: আদর্শ one.com/Ue9rT8
বেজম্যাক্স

ভাল ইনপুট, অনুশীলনে কখনও এই সমস্যা ছিল না। আমি আমার পোস্ট আপডেট করব, আপনাকে অনেক ধন্যবাদ! এবং আমি এই লোকেল বিশেষগুলির জন্য পরীক্ষার উন্নতি করব কেবলমাত্র কোথায় সমস্যার সম্মুখীন হবে তা জানতে।
user3227576

1
আমি বিভিন্ন লোকেল এবং বিভিন্ন সংখ্যার জন্য সমাধানটি পরীক্ষা করে দেখেছি ... এবং আমাদের সকল কাজের জন্য, কারণ আমাদের সর্বদা দশমিক পয়েন্ট সহ সংখ্যা থাকে (আমরা একটি পাঠ্য ফাইল থেকে অর্থ-মানগুলি পড়ছি) reading আমি উত্তরে একটি সতর্কতা যুক্ত করেছি।
user3227576

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

আপনার স্ট্রিং থেকে অঙ্কগুলি এবং বিন্দু ব্যতীত সমস্ত অক্ষর মুছে ফেলবে।

এটা লোকেল-সচেতন করতে, আপনাকে ব্যবহার করতে চাইতে পারেন getDecimalSeparator()থেকে java.text.DecimalFormatSymbols। আমি জাভা জানি না, তবে এটি দেখতে দেখতে এটির মতো হতে পারে:

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

যা আমেরিকানবিহীন সংখ্যাগুলির জন্য অপ্রত্যাশিত ফলাফল দেবে - জাস্টিনের উত্তরের মন্তব্যগুলি দেখুন।
পিয়েটার তুরিক

2

পুরানো বিষয় তবে সম্ভবত সবচেয়ে সহজ হ'ল অ্যাপাচি কমন্স নম্বর ইউটিল ব্যবহার করা যা একটি পদ্ধতি তৈরি করে বিগডেসিমাল (স্ট্রিংয়ের মান) ....

আমার ধারণা (আশা) এটি লোকেলগুলিকে অ্যাকাউন্টে নেয় বা অন্যথায় এটি অকেজো হয়ে যায়।


যেমন বর্ণিত createBigDecimal, শুধুমাত্র নতুন BigDecimal (STRING) জন্য একটি মোড়কের হয় NumberUtils সোর্স কোড যা কোন লোকেল আমি যতদূর জানি বিবেচনায়
মার্চ বার

1

এটি আমার জন্য এটি চেষ্টা করে দেখুন

BigDecimal bd ;
String value = "2000.00";

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

2
এই পদ্ধতিতে দশমিক পয়েন্ট এবং থ্রোহ্যান্ডস গ্রুপগুলির জন্য কাস্টম ডিলিমিটার নির্দিষ্ট করে সমর্থন করে না।
বেজম্যাক্স

হ্যাঁ, তবে এটি হ্যাশম্যাপের মতো অবজেক্ট থেকে স্ট্রিং বিগডিসিমাল মান পেতে এবং অন্যান্য পরিষেবাগুলিতে কল করার জন্য বিগডিসিমাল মানকে সঞ্চয় করার জন্য
রাজকুমার টেক্রাফট

1
হ্যাঁ, তবে প্রশ্নটি ছিল না।
বেজম্যাক্স

আমার জন্যও কাজ করে
সত্যেশ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.