2

I have a text file that contains the following:

Hello
1
2
3
4
5.6
LOL
23.5
34.6
23
456
Rofl.

I wrote down the code in java that would read the contents of this text file and distinguish between the 3 data types.I used try catch statements and my code works(kinda). The only problem is that it converts any whole numbers to doubles as well. For example the following is what my code is outputting:

List of integers in the textfile: [1, 2, 3, 4, 23, 456]

List of doubles in the textfile: [1.0, 2.0, 3.0, 4.0, 5.6, 23.5, 34.6, 23.0, 456.0]

List of Strings in the textfile: [Hello, 5.6, LOL, 23.5, 34.6, Rofl]

I want to prevent that from happening. Any suggestions would be appreciated.

    ArrayList<Integer> data_int=new ArrayList<Integer>();
    ArrayList<String> data_String=new ArrayList<String>();
    ArrayList<Double> data_double=new ArrayList<Double>();


    while(file.hasNext())
    {
        String s=file.next();
        System.out.println(s);

        try
        {
            Integer.parseInt(s);
            data_int.add(Integer.parseInt(s));
         }
        catch(NumberFormatException e)
        {
          data_String.add(s);
        }

        try
        {
              Double.parseDouble(s);
              data_double.add(Double.parseDouble(s)); 

        }
        catch(NumberFormatException e)
        {

        }

    }
    System.out.println("List of integers in the textfile: "+data_int);
    System.out.println("List of doubles in the textfile: "+data_double);
    System.out.println("List of Strings in the textfile: "+data_String);
dimo414
  • 47,227
  • 18
  • 148
  • 244
12dec1990
  • 115
  • 1
  • 9
  • This link has a pretty solid answer: http://stackoverflow.com/questions/9898512/how-to-test-if-a-double-is-an-integer – Sean May 29 '15 at 20:24

5 Answers5

1

Try the following with each token received:

  1. Attempt to parse the token as a int - if that passes do not attempt to parse it as an int or String.
  2. If that fails attempt to parse the token as an double. If that passes do not attempt to parse it as a String.
  3. If that fails parse the token as a String.

Remove the code where you add the data to the String datset when each prior parse attempt fails.

Amir Afghani
  • 37,814
  • 16
  • 84
  • 124
  • 2
    You probably mean he needs to try parse it as an int first, because a double will parse both an integer value and a double, while a parseint will only parse an integer value and not a double. – Pavlin May 29 '15 at 20:21
  • 1+ to the comment above – Marcin D May 29 '15 at 20:21
1

Put your double check in the catch block for the integer check

try {
  Integer.parseInt(s);
  data_int.add(Integer.parseInt(s));
} catch(NumberFormatException e) {
  try {
    Double.parseDouble(s);
    data_double.add(Double.parseDouble(s));
  } catch(NumberFormatException e) {
    data_String.add(s);
  }
}
dimo414
  • 47,227
  • 18
  • 148
  • 244
ControlAltDel
  • 33,923
  • 10
  • 53
  • 80
  • Just so I'm clear with the explanation behind this code,the 1st try parses integers.If that doesn't work,there is another try within the catch statement that parses it into doubles.And if that doesn't work,it is considered a string.Correct? – 12dec1990 May 30 '15 at 16:47
0

I think below should work for you.

while(file.hasNext()){
        String s=file.next();
        System.out.println(s);  

        try
        {
              try
               {
                Integer.parseInt(s);
                data_int.add(Integer.parseInt(s));
               }
               catch(NumberFormatException e){
                //do nothing
               }
              Double.parseDouble(s);
              data_double.add(Double.parseDouble(s)); 
        }
        catch(NumberFormatException e){
        data_String.add(s);
        }
    }
dReAmEr
  • 6,986
  • 7
  • 36
  • 63
0

Instead of calling parseInt or parseDouble and then dealing with the exception, perhaps it would be better to use a regex with String#matches to see if the value looks like an integer or a double. Exceptions are for exceptional circumstances that happen outside normal flow; you don't want to use them to control the regular flow of your program. Since you can expect there to be non-numerical values, it is better to check the value and see what it "looks like".

To see if it is an integer, you can just use -?\\d+.

For doubles, use the regex -?\\d*\\.\\d+. This will even match strings of the form .5.

If none of these match, it is probably a string.

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
  • Your integer regex won't match negatives, and your double regex won't match exponent notation. Since *at best* your regexes would simply predict what `parseInt` and `parseDouble` do already, it seems unhelpful to attempt to define the right regex - just let the existing parsers do it for you. – dimo414 May 29 '15 at 20:24
  • @dimo414 It is trivial to change the regex to match negative numbers. Since the OP hasn't specified that he is dealing with exponent notation, I didn't see a need to include that in the regex, but it would be trivial to include that as well. Using exceptions for control flow completely sidesteps what exceptions are *actually* for. Furthermore, your performance is going to be terrible since you're dealing with *two* exceptions being thrown every time you encounter a non-numerical value. – Vivin Paliath May 29 '15 at 20:27
  • Of course you can tidy up the regexes, but whenever you eventually correctly match against all parsable ints and doubles, you've simply replicated the behavior of `parseInt` and `parseDouble`, then when you actually run them they have to needlessly re-validate the string. Without benchmarking it's a waste of breath for either of us to conjecture as to which is worse, but at a minimum neither is a clear winner. On the other hand the added code complexity of pre-validating is relatively high. I respect what you're getting at, but at least personally, I wouldn't do it. – dimo414 May 29 '15 at 21:22
  • How many "all parseable ints" are there? `-?\d+` will match any integer, and [`[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?`](http://www.regular-expressions.info/floatingpoint.html) will match floating-point numbers (including exponents). The problem is that Java doesn't provide "try parse" functionality, which *necessitates* duplication if you want to get around the performance hit. [Here's](https://gist.github.com/vivin/efd0adee9876c5a63fd5) a quick benchmark; parsing is almost *five times slower* than using the regex (on my box; YMMV). Pre-validating isn't even that much more complex. – Vivin Paliath May 29 '15 at 21:54
  • Another example: 2^32 passes your regex, but is not a valid int. – dimo414 May 29 '15 at 22:40
  • @dimo414 How would `2^32` match against `-?\d+`? In Java `Matcher#matches` tries to match the *entire region*. So `-?\d+` is actually equivalent to `^-?\d+$`, which most definitely won't match against `2^32`. In the regexes I provided above, the anchors `^` and `$` are implicit. – Vivin Paliath May 29 '15 at 23:21
  • 2^32, also known as 4294967296, is larger than an `int` can hold, yet matches your regex. – dimo414 May 30 '15 at 06:00
  • And it is easy to deal with that too. Either use `BigInteger` or `Long` or catch the `NumberFormatException` *in this case*. Only in the worst case (all strings greater than `Integer.MAX_VALUE`) would performance be as bad as the try-catch approach. While I agree in general with your sentiment about duplicating functionality, you would be hard pressed to convince me that it is worth it to avoid duplication in exchange for a 5x performance hit. – Vivin Paliath May 30 '15 at 06:49
0

Use nested Try Catch Block:

while (file.hasNext()) {

    String s = file.next();
    System.out.println(s);

    try {
        Integer.parseInt(s);
        data_int.add(Integer.parseInt(s));
    } catch (Exception e) {

        try {
            Double.parseDouble(s);
            data_double.add(Double.parseDouble(s));
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            data_String.add(s);
        }
    }

}
Rajesh
  • 2,135
  • 1
  • 12
  • 14