Reputation: 19
So at the input, a string contains different types of data. Basically, this is a string, int, and float. I check types through Float.parseFloat()
and Integer.parseInt()
. the Integer.parseInt()
works correctly, yet Float.parseFloat()
includes all the digits that are checked. How to avoid this?
The problem is that when checking for the float type, it also considers ints (output):
public class TypeCountString {
public static void countTypeInString(String string){
String[] value = string.split(" ");
float ifFloat;
int ifInt;
String ifString;
int counter = 0;
// count Floats
for (String i: value){
try{
ifFloat = Float.parseFloat(i);
counter++;
continue;
} catch (NumberFormatException e){
}
}
System.out.println("Float " + counter);
//count ints
counter = 0;
for (String i: value){
try{
ifInt = Integer.parseInt(i);
counter++;
continue;
} catch (NumberFormatException e){
}
}
System.out.println("Int " + counter);
//counts strings
String stringOfStrings = string.replaceAll("[0-9.]","");
stringOfStrings = stringOfStrings.replaceAll(" "," ");
String[] value2 = stringOfStrings.split(" ");
System.out.println("String " + value2.length);
}
public static void main(String[] args) {
String string = "Hello my 50 name 4.5 is James, I 20 years old and i have 5.7 coins";
System.out.println(string);
countTypeInString(string);
}
}
Upvotes: 1
Views: 13348
Reputation: 7130
Parsing first each substring to float
will also parse integers as such, since integers are a subset of real numbers.
You should instead start parsing to the most restrictive type (in terms of possible values) up to the least restrictive. In your case, the possible values are: integers, real numbers, and strings. Therefore, you could try first to parse each substring to integer. If it fails, try to parse it as a real number. If that fails too, just treat it as a String
.
Starting with integers is critical, as a decimal separator can't ever appear in an integer, leaving no doubts on what we're parsing, while with real numbers, a separator may or may not appear.
To handle each parsing, just use a try-catch
, and nest each attempt in a catch
block that handles NumberFormatException
. Here is a possible implementation:
public class Main {
public static void main(String[] args) {
countTypesInString();
}
public static void countTypesInString() {
String str = "Hello my 50 name 4.5 is James, I 20 years old and i have 5.7 coins";
String[] vetStr = str.split("\\s+");
List<Integer> listInt = new ArrayList<>();
List<Float> listFloat = new ArrayList<>();
List<String> listStr = new ArrayList<>();
for (String s : vetStr) {
try {
// attempt int parsing
listInt.add(Integer.parseInt(s));
} catch (NumberFormatException exInt) {
try {
// attempt float parsing
listFloat.add(Float.parseFloat(s));
} catch (NumberFormatException exFloat) {
// just treat it as a String
listStr.add(s);
}
}
}
System.out.println("Number of ints: " + listInt.size() + " => " + listInt);
System.out.println("Number of floats: " + listFloat.size() + " => " + listFloat);
System.out.println("Number of strings: " + listStr.size() + " => " + listStr);
}
}
Output:
Number of ints: 2 => [50, 20]
Number of floats: 2 => [4.5, 5.7]
Number of strings: 12 => [Hello, my, name, is, James,, I, years, old, and, i, have, coins]
As a side note, you might want to use double
instead of float
to represent real numbers, as the former offers a higher precision compared to the latter. In fact, Java treats decimal literals as a double
by default.
Upvotes: 2
Reputation: 5794
Some tokens (like "50") are parseable both as integer and float. Your code gives both of them a chance, even though your intention is to only count each token as one type or the other (so count "50" as an integer, not as a float).
A simple fix could be to modify your float check to be:
i
can pass Float.parseFloat()
, andi
contains a decimal pointThat code edit could look like this:
Float.parseFloat(i);
if (i.contains(".")) {
counter++;
continue;
}
Or, as a more involved alternative, instead of checking all input tokens for floats, then re-checking all input tokens for integers, I would take a different approach.
First, I would change the code to stop checking the entire input string repeatedly. This is helpful for 2nd part below, but also cleans up an unnecessary inefficiency of re-checking tokens even if you've already identified their data type. If you had a large number of tokens, it's wasteful to try parsing all of them as float, then try all of them as integer, then try a third time to count plain strings.
Second, since you would be checking (and counting) each token only one time, you could:
Integer.parseInt()
, increment that counter and move on to the next tokenFloat.parseFloat()
without looking for decimal; if it worked then bump counter, move to next tokenString
so simply bump the counter, then next tokenUpvotes: 2
Reputation: 61
As Integer is a sub-type of Float, Float will count in Integers into your float count. If you solely just want the number of float that is not integer, just take float count minus integer count.
Upvotes: 2