I am creating a physics calculator and currently working on average velocity. For displacement I would like the user to input a string i.e. "5km north". Then using a method assign only the numeric values in the string to be doubles using Double.parseDouble or something of the like.
Below is my method to pull out numeric values
private double getNumericalValue(String userInput) {
double numericalOutput = 0.0;
for (int i = 0; i < userInput.length(); i ) {
if (userInput.charAt(i) >= 65 && userInput.charAt(i) <= 122) {
numericalOutput = Double.parseDouble(userInput.substring(0, i));
}
}
return numericalOutput;
}
and lastly the getAverageVelocity method
private void getAverageVelocity() {
// formula average velocity = displacement s / change in time t
double avgVelocity = 0.0;
System.out.println("Enter the displacement: [ex. 5 km north]");
String displacement = getStringInput();
System.out.println("Enter the change in time: [ex. 1 hour]");
String changeInTime = getStringInput();
// parse the string and change numerical input into double
double numericalS = getNumericalValue(displacement);
double numericalT = getNumericalValue(changeInTime);
avgVelocity = numericalS / numericalT;
System.out.println("The Average Velocity is: " avgVelocity);
}
As you can see I figured I could simply compare chars to their ascii value. However, it is including the k or a space in my double output which is throwing this error.
Exception in thread "main" java.lang.NumberFormatException: For input string: "5 k"
at java.base/jdk.internal.math.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2054)
at java.base/jdk.internal.math.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.base/java.lang.Double.parseDouble(Double.java:556)
at Main.getNumericalValue(Main.java:122)
at Main.getAverageVelocity(Main.java:393)
at Main.kineticsIn1DCalculator(Main.java:375)
at Main.performAction(Main.java:141)
at Main.runner(Main.java:29)
at Main.main(Main.java:22)
Any help and a thorough explanation would be great. Thanks.
CodePudding user response:
What you are actually testing in the if block is whether the character at i is a letter A-Z, a-z and other symbols(i.e. [ ^ ], ...etc) to check if it's a number (i.e. 0-9) the corresponding decimal range is 48-57 check this link
as for the exception it's because of substring(0, 0) will result in an empty string, and when trying to parse it, Double.parseDouble() will throw an exception. here is a solution you can use:
private double getNumericalValue(String userInput) {
double numericalOutput = 0.0;
for (int i = 0; i < userInput.length(); i ) {
if (userInput.charAt(i) >= 48 && userInput.charAt(i) <= 57) {
numericalOutput = Double.parseDouble(userInput.substring(0, i 1));
}
}
return numericalOutput;
}
Note: substring(i, j) i is inclusive, j exclusive
Update : just noticed, in your case the exception happens because you are trying to parse the letter "k" since it passes the condition, resulting in Double.parseDouble() throwing an exception.
CodePudding user response:
You have the error because even if the first number is found the for
loop continues. You simply have to add break
instruction, then the for loop ends at the first number found.
This is the final code of the method getNumericalValue
:
private double getNumericalValue(String userInput) {
double numericalOutput = 0.0;
for (int i = 0; i < userInput.length(); i ) {
if (userInput.charAt(i) >= 65 && userInput.charAt(i) <= 122) {
numericalOutput = Double.parseDouble(userInput.substring(0, i));
break;
}
}
return numericalOutput;
}
CodePudding user response:
You simply should input the line and parse its parts.
Best to introduce a class to hold a value with unit, where "km north" counts as a unit.
Since java 14 there exists the record
class.
record ValueWithUnit(double value, String unit) {
public static ValueWithUnit from(String s) {
String v = s.replaceFirst("^(.*?)([ A-z].*)$", "$1");
String u = s.replaceFirst("^(.*?)([ A-z].*)$", "$2");
if (u == v) {
u = "";
}
double x = Double.parseDouble(v); // Replaces getNumericalValue(v);
return new Value(x, u);
}
@Override
public String toString() {
String.format("%f %s", value, unit);
}
}
You could use it directly as:
ValueWithUnit vu = new ValueWithUnit(30.0, "km");
System.out.println(vu);
The code then becomes:
private void getAverageVelocity() {
// formula average velocity = displacement s / change in time t
double avgVelocity = 0.0;
System.out.println("Enter the displacement: [ex. 5 km north]");
ValueWithUnit displacement = ValueWithUnit.from(getStringInput());
System.out.println("Enter the change in time: [ex. 1 hour]");
ValueWithUnit changeInTime = ValueWithUnit.from(getStringInput());
// parse the string and change numerical input into double
double numericalS = displacement.value;
double numericalT = changeInTime.value;
avgVelocity = numericalS / numericalT;
System.out.printf("The Average Velocity is: %f %s%n", avgVelocity,
displacement.unit "/" changeInTime.unit);
}