0

I want to parse a string in the format '5.3984.234' and convert it to a float. Obviously the float will be 5.3984

In C, using atof() will give this result, but in Java, Float.parseFloat() and Float.valueOf() both throw exception.

I do not want the function throwing an exception and want the identical functionality of atof() How can I do this?

Note: I can't guarantee there is always two periods in the string. Sometimes it might be 48328.458, other times 4823.5482.4822 or even 42894.4383.8349.439

user1054922
  • 2,101
  • 2
  • 23
  • 37
  • Did you read the exception message when using `Float#parseFloat`? – Luiggi Mendoza Nov 12 '13 at 15:26
  • 2
    You can use `DecimalFormat.parseObject` method to find the longest possible prefix and then parse it. http://docs.oracle.com/javase/7/docs/api/java/text/Format.html#parseObject%28java.lang.String,%20java.text.ParsePosition%29 – Grzegorz Żur Nov 12 '13 at 15:29

5 Answers5

2

One option is to use StringTokenizer, using . as the separator, and then use only the first two tokens for conversion.

givanse
  • 14,503
  • 8
  • 51
  • 75
  • 1
    the only trouble with this, is String Tokenizer will break up the number based on the token, so rather than getting '59234.2342' you'll get ['59234'], [2342] which you'd then have to re-combine into a double. Could be a pain. – WillBD Nov 12 '13 at 15:31
  • After using the tokenizer, you still have strings, no conversion has been done yet. So, combining them is as easy as `token1 + "." + token2`. From there you can safely proceed to `parseFloat()` – givanse Nov 12 '13 at 15:36
2

Well, first and foremost atof() can return undefined behaviour, so I wouldn't want to emulate that exactly ;) see:

atof() with non-nullterminated string

for what I mean by that.

Anyway, to solve you problem using Java, I would approach it with a String.substring method, where you simply parse the string up until the second '.', and then do whatever of the functions you'd like with it. Albeit, if you don't care about throwing away everything after the second '.' it gets a lot easier.

And here's some code to make what I mentioned work:

public class main{
public static void main(String[] args)
{
    String test = "5.3984";
    int tempIndex = 0;

    tempIndex = test.indexOf('.');
    tempIndex =  test.indexOf('.', tempIndex + 1 );
    if (tempIndex != -1)
    {
        System.out.println("multiple periods: " + Float.parseFloat(test.substring(0, tempIndex)));
    }
    else 
    {
        System.out.println("Only one Period: :" + Float.parseFloat(test));
    }
}

Now, this may not be super robust, but it seems to work ok.

Community
  • 1
  • 1
WillBD
  • 1,919
  • 1
  • 18
  • 26
  • Thanks. This doesn't handle strings without a decimal point (I know, not in my original question..), but I modified it and it works great. – user1054922 Nov 12 '13 at 16:02
  • No Problem! I didn't check every border case, just the big ones. But I'm glad you were able to modify it to do what you needed, good luck! – WillBD Nov 12 '13 at 16:04
1

Double.parseDouble() always processes the whole String. Since you have to decimal points in it, it will throw a NumberFormatException. I am also not convinced yours is the obvious result. The input is either malformed or locale dependent (you could also expect a value of 53984234).

Axel
  • 13,939
  • 5
  • 50
  • 79
0

In Java you can do this:

//this only works if the string has exactly two points (two '.' characters)
//(sorry, I misread the question)
//String string = "1.2341.234";
//float f = Float.parseFloat(string.substring(0, string.lastIndexOf(".")));



    //for any number of points in the string:  
    String string = "1.2.3";
    String[] elems = string.split("\\.");
    float f = Float.parseFloat(elems.length==1 ? string : elems[0]+"."+elems[1]);
Shivan Dragon
  • 15,004
  • 9
  • 62
  • 103
  • It will throw NumberFormatException if the string has three dots. Extra pre-processing would be required. – givanse Nov 12 '13 at 15:31
0

You need to separate the proper leading floating point representation from the additional data following it. This is what I would do:

Pattern p = Pattern.compile("^(-?\\d+(\\.\\d+)?)");
Matcher m = p.matcher(stringWithFloatInIt);
if (m.find()) {
    f = Float.parseFloat(m.group(0));
} else {
    // String was not even CLOSE to a number
}
Charles Forsythe
  • 1,831
  • 11
  • 12