Numeric values from a String - java

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.

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.

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;
}

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);
}

Related

Converting double to String in order to read a txt file [duplicate]

How can I convert a String such as "12.34" to a double in Java?
You can use Double.parseDouble() to convert a String to a double:
String text = "12.34"; // example String
double value = Double.parseDouble(text);
For your case it looks like you want:
double total = Double.parseDouble(jlbTotal.getText());
double price = Double.parseDouble(jlbPrice.getText());
If you have problems in parsing string to decimal values, you need to replace "," in the number to "."
String number = "123,321";
double value = Double.parseDouble( number.replace(",",".") );
To convert a string back into a double, try the following
String s = "10.1";
Double d = Double.parseDouble(s);
The parseDouble method will achieve the desired effect, and so will the Double.valueOf() method.
double d = Double.parseDouble(aString);
This should convert the string aString into the double d.
Use new BigDecimal(string). This will guarantee proper calculation later.
As a rule of thumb - always use BigDecimal for sensitive calculations like money.
Example:
String doubleAsString = "23.23";
BigDecimal price = new BigDecimal(doubleAsString);
BigDecimal total = price.plus(anotherPrice);
You only need to parse String values using Double
String someValue= "52.23";
Double doubleVal = Double.parseDouble(someValue);
System.out.println(doubleVal);
Citing the quote from Robertiano above again - because this is by far the most versatile and localization adaptive version. It deserves a full post!
Another option:
DecimalFormat df = new DecimalFormat();
DecimalFormatSymbols sfs = new DecimalFormatSymbols();
sfs.setDecimalSeparator(',');
df.setDecimalFormatSymbols(sfs);
double d = df.parse(number).doubleValue();
String double_string = "100.215";
Double double = Double.parseDouble(double_string);
There is another way too.
Double temp = Double.valueOf(str);
number = temp.doubleValue();
Double is a class and "temp" is a variable.
"number" is the final number you are looking for.
This is what I would do
public static double convertToDouble(String temp){
String a = temp;
//replace all commas if present with no comma
String s = a.replaceAll(",","").trim();
// if there are any empty spaces also take it out.
String f = s.replaceAll(" ", "");
//now convert the string to double
double result = Double.parseDouble(f);
return result; // return the result
}
For example you input the String "4 55,63. 0 " the
output will the double number 45563.0
Using Double.parseDouble() without surrounding try/catch block can cause potential NumberFormatException had the input double string not conforming to a valid format.
Guava offers a utility method for this which returns null in case your String can't be parsed.
https://google.github.io/guava/releases/19.0/api/docs/com/google/common/primitives/Doubles.html#tryParse(java.lang.String)
Double valueDouble = Doubles.tryParse(aPotentiallyCorruptedDoubleString);
In runtime, a malformed String input yields null assigned to valueDouble
Used this to convert any String number to double when u need int just convert the data type from num and num2 to int ;
took all the cases for any string double with Eng:"Bader Qandeel"
public static double str2doubel(String str) {
double num = 0;
double num2 = 0;
int idForDot = str.indexOf('.');
boolean isNeg = false;
String st;
int start = 0;
int end = str.length();
if (idForDot != -1) {
st = str.substring(0, idForDot);
for (int i = str.length() - 1; i >= idForDot + 1; i--) {
num2 = (num2 + str.charAt(i) - '0') / 10;
}
} else {
st = str;
}
if (st.charAt(0) == '-') {
isNeg = true;
start++;
} else if (st.charAt(0) == '+') {
start++;
}
for (int i = start; i < st.length(); i++) {
if (st.charAt(i) == ',') {
continue;
}
num *= 10;
num += st.charAt(i) - '0';
}
num = num + num2;
if (isNeg) {
num = -1 * num;
}
return num;
}
String s = "12.34";
double num = Double.valueOf(s);
Try this,
BigDecimal bdVal = new BigDecimal(str);
If you want Double only then try
Double d = Double.valueOf(str);
System.out.println(String.format("%.3f", new BigDecimal(d)));

Validate a String to Double with max digits

For example when I parse a string "12345678901234567890" to double using Double.parseDouble() it returns the value "12345678901234567000" since it can hold up to 17 digits.
I want to validate this scenario and the user should be allowed to pass only 17 digits. How do I do this?
Example :
1.2345678901234567890 is invalid because it has more than 17 digits total
1.2345E+10 is valid
Tried something like this which can count the digits using split function
String input="12345678901234567E100";
String inputWithoutSign;
int lengthFullNumber;
int lengthFraction;
double v = Double.parseDouble(input);
if(input.startsWith("+") || input.startsWith("-")){
inputWithoutSign = input.split("[-+]",2)[1];
}
else inputWithoutSign = input;
String num = inputWithoutSign.split("[eE]", 2)[0];
if(num.indexOf('.') == -1){
lengthFullNumber = num.length();
lengthFraction = 0;
}else{
String[] splitNum = num.split("\\.", 2);
lengthFullNumber = splitNum[0].length();
lengthFraction = splitNum[1].length();
}
System.out.println("length:"+(lengthFullNumber+lengthFraction));
Presuming I understand your goal of limiting the number of digits, this may help solve the problem.
Test cases
String[] vals = {
"12345678901234567890", "123456789091919191919",
"182828282.18282828", "182828282.182828282", "191929e10",
"192929.22929e10"
};
Try and parse them
for (String v : vals) {
// remove possible decimal point and signs
String test = v.replaceAll("[.+-]", "");
// remove any exponents at end of string
test = test.replace("\\D+.*", "");
if (test.length() > 17) {
System.out.println(v + " has too many digits");
continue;
}
double d = Double.parseDouble(v);
System.out.println(v + " parses to " + d);
}

Parse double without mantissa and exponent separator

I have to read double from data files with the following format
1.234+5 // = 1.234e+5
1.234-5 // = 1.234e-5
I can't change the format and I have to parse millions/billions double from data files(= method should be efficient) .
Can I provide a decimal format or is there a convenient method (available in java jdk) able to parse these doubles ?
Double.parseDouble("1.234+5"); // throws NumberFormatException
Scanner scanner = new Scanner("1.234+5");
Scanner.nextDouble(); // throws InputMismatchException
EDIT 1
Precision for what i call data files :
Data files are ENDF formatted file which is a really strict format (300 pages manual) and here is an extract of one of these files
9.223500+4 2.330248+2 0 0 0 63515 8457
2.22102+16 1.57788+13 0 0 6 03515 8457
4.170051+4 1.312526+3 1.641191+5 1.625818+3 4.413323+6 1.648523+53515 8457
I can parse integers with a simple
Integer.parseInt()
But i can't with double.
You can use a regex to insert an e which is then parseable in the normal way:
private static final Pattern INSERT_EXPONENT = Pattern.compile("(.*)([+-].*)");
System.out.println(INSERT_EXPONENT.matcher("1.234+5").replaceFirst("$1e$2"));
System.out.println(INSERT_EXPONENT.matcher("1.234-5").replaceFirst("$1e$2"));
This is just quick&dirty and doesn't guard against invalid input.
Here is my attempt. I don't know if this is what you are looking for, but this will convert the number into a double format. Hope this will help.
String temp = "1.234+5";
StringBuilder str = new StringBuilder(temp);
for(int index = temp.length() - 1; index > 0; index--)
{
//this will look for a + or - symbol in your string
if(temp.charAt(index) == '+' || temp.charAt(index) == '-') {
str.insert(index, 'e'); //this will insert e before the symbol
break;
}
}
temp = str.toString();
System.out.println(temp);
double a= Double.parseDouble(temp); //convert the string back to a double
System.out.println(a); //this is just to test the output
double b = 1.234e+5;
System.out.println(b);
You will probably need a regex.
private void test() {
String [] test = {"1.234+5", "-1.234-2"};
for (String s : test) {
System.out.println(s + " -> " + parse(s));
}
}
private static final Pattern FindMissingE = Pattern.compile("([+-]{0,1}[0-9.]+)([+-]{0,1}[0-9]+)");
private double parse(String s) {
Matcher m = FindMissingE.matcher(s);
if(m.find()) {
return Double.parseDouble(m.replaceFirst("$1e$2"));
}
return 0.0;
}

Convert decimal to IEEE Binary

I am trying to convert a number from decimal value to its IEEE 752 form. For example:
+43.9542 -> 01000010001011111101000100011010
-43.9542 -> 11000010001011111101000100011010
And I have written this method:
public float GetFloat32(String numero) {
//Convert
int intBits = Integer.parseInt(numero, 2);
float myFloat = Float.intBitsToFloat(intBits);
//Exponent
getExponent = 127 + (String.valueOf(Integer.toBinaryString(Math.abs((int) myFloat))).length() - 1);
//Sign
getSign = (myFloat < 0) ? 1 : 0;
return myFloat;
}
There is a problem that I cannot solve. I will make another example to make it clear.
double a = k.GetFloat32("01000010001011111101000100011010")
a = 43.9542
But when the number is negative, such as
double a = k.GetFloat32("1000010001011111101000100011010")
I get this error:
It means that my code works perfectly with positive numbers (including the zero) but with negative numbers it crashes. Where is the problem?
Note
I thought that I could solve my problem in this way
Check if String numero has a charAt(0) equal at 1
If yes (numero.charAt(0) == 1) then remove the first char
Call GetFloat32() with the new number (without the 1)
Return the result adding the - in front of the num
This could work but I would like to know where is the problem in the method above. I'd prefer avoiding this solution if possible.
The problem is that int/Integer has an upper limit of 0x7FFF_FFFF and so the Integer.parseInt method won't go beyond this limit.
Use Long.parseLong, check the resulting value for exceeding 0x7FFF_FFFFL and handle according to the logic required for negative integer values.
Although, I don't see anything bad in your very own idea of stripping the sign bit and dealing with the rest to get the absolute value.
Edit There isn't a way to get the encoded float with a simple integer conversion from a bit string. Just consider that +1 and -1 in 32 binary digits according to two's complement representation differ in more than one bit, and 100....000 isn't -0. Signed magnitude isn't the same as two's complement. Moreover, Java's binary and hexadecimal (or any other base's) literals are meant to be positive quantities; if you need a negative value, use a sign.
Later Method Integer.parseUnsignedInt doesn't have an advantage over using Long, since you'll then have to know how use two's complement arithmetic to remove the leading (sign) bit to produce the absolute value which can then be split into exponent and mantissa. (Add or subtract Integer.MIN_VALUE.)
If there isn't IEEE 752 and IEEE 754 is the target format, the easiest form is
float f1 = Float.intBitsToFloat(Integer.parseUnsignedInt(numerio,2));
public class IEEE754ToFloatingValues {
public static double convertToInt(String mantissa_str) {
int power_count = -1;
double mantissa_int = 0.0;
for (int i = 0; i < mantissa_str.length(); i++) {
// System.out.print(Integer.parseInt(mantissa_str.charAt(i) + ""));
mantissa_int += (Integer.parseInt(mantissa_str.charAt(i) + "") * Math.pow(2, power_count));
power_count -= 1;
}
IEEE754ToFloatingValues.logger.info((Object) "IEEE754ToFloatingValues : convertToInt :: end");
return mantissa_int + 1.0;
}
public static String convertToBinary(int i) {
return Integer.toBinaryString(i + 0b10000).substring(1);
}
public static String decimalToHex(String decimal) {
int i = Integer.parseInt(decimal);
System.out.println("<<>>" + i);
String my_hexdata = Integer.toHexString(i);
System.out.println(my_hexdata);
return String.valueOf(ReturnFloatingValue(my_hexdata));
}
public static double ReturnFloatingValue(String my_hexdata) {
String myString = "";
if (my_hexdata == null) {
return -2.0;
}
if (my_hexdata.length() != 8) {
myString = String.format("%1$-" + 8 + "s", my_hexdata).replace(' ', '0');
System.out.println("My hex data after appending 0's is : " + myString);
}
String binary = "";
for (int i = 0; i < myString.length(); i++) {
int num = Integer.parseInt(myString.charAt(i) + "", 16);
binary += convertToBinary(num);
}
System.out.println("Binary length is : " + binary.length());
System.out.println("Binary number is : " + binary);
if (binary == null || binary.isEmpty()) {
return -3.0;
}
String ieee_32 = binary.substring(2);
ieee_32 = String.format("%1$-32s", binary).replace(' ', '0');
long sign_bit = Long.parseLong(new StringBuilder().append(ieee_32.charAt(0)).toString());
long exponent_bias = Long.parseLong(ieee_32.substring(1, 9), long exponent_unbias = exponent_bias - 127L;
System.out.println("Exponent unbias is : " + exponent_unbias);
String mantissa_str = ieee_32.substring(9);
double mantissa_int = convertToInt(mantissa_str);
double real_no = Math.pow(-1.0, (double) sign_bit) * mantissa_int * Math.pow(2.0, (double) exponent_unbias);
System.out.println("Real no is : " + real_no);
return real_no;
}
public static void main(String[] args) {
//decimalToHex("0");
}
}
import java.util.*;
public class IEEE754 {
public static void main(String[] args) {
float floa;
Scanner sc = new Scanner(System.in);
System.out.println("ENTER A FLOATING POINT NUMBER");
floa=sc.nextFloat();
int no,sign;
no=(int) floa;
String a= Integer.toBinaryString(no);
String sub=a.substring(1, a.length());
if(floa<0)
{
sign=1;
}
else
{
sign=0;
}
int exp=a.length()-1;
System.out.println(exp);
int be=127+exp;
String b= Integer.toBinaryString(be);
System.out.print("biased exponent->");
System.out.println(b);
int loop=23-exp;
float floatpart =floa-no;
int q[]=new int[25];
for(int i=1,j=0;i<=loop;i++,j++)
{
q[j]=(int) (floatpart*2);
floatpart=floatpart*2;
if(q[j]==1){
floatpart=floatpart-1;
}
}
System.out.print("mantissa->");
System.out.print(sub);
for(int k=0;k<q.length;k++)
System.out.print(q[k]);
System.out.println();
System.out.println("IEEE754 FORMAT IS");
System.out.print(sign+" "+b+" ");
System.out.print(sub);
for(int k=0;k<q.length;k++)
System.out.print(q[k]);
}
}

Android - Convert Arch to Decimal

I'm creating a feet and inches calculator. I want the user to be able to enter the information in various ways such as 1'-4-5/8" or 1 4 5/8.
When performing math, the above numbers will have to be converted to decimal (1'-4-5/8" is 16.625 in decimal inches). The final result will be in either decimal inches or then converted back to feet and inches.
How would I go about parsing the architectural measurement and converting it into decimal inches?
Any help would be greatly appreciated!
Thank you!
edit:
After way too much time and trying many different things, I think I got something that will work. I'm ultimately going to limit the way the user can enter the length so I think the following is going to work. It may not be optimized but it's the best I can get right now.
public class delim_test_cases {
public static void main(String[] args) {
double inches = 0;
double feet = 0;
double fract = 0;
String str = "2'-3-7/8";
String[] TempStr;
String delimiter = ("[-]+");
TempStr = str.split(delimiter);
for(int i=0; i< TempStr.length ; i++ ) {
for(int z=0; z< TempStr[i].length() ; z++ ) {
if (TempStr[i].charAt(z) == '\'') {
String[] FeetStr;
String feetdelim = ("[\']+");
FeetStr = TempStr[i].split(feetdelim);
feet = Integer.parseInt(FeetStr[0]);
}
else if (TempStr[i].charAt(z) == '/') {
String[] FracStr;
String fracdelim = ("[/]+");
FracStr = TempStr[i].split(fracdelim);
double numer = Integer.parseInt(FracStr[0]);
double denom = Integer.parseInt(FracStr[1]);
fract = numer/denom;
}
else if (TempStr[i].indexOf("\'")==-1 && TempStr[i].indexOf("/")==-1) {
String inchStr;
inchStr = TempStr[i];
inches = Integer.parseInt(inchStr);
}
}
}
double answer = ((feet*12)+inches+fract);
System.out.println(feet);
System.out.println(inches);
System.out.println(fract);
System.out.println(answer);
}
}
Why not just split on either the '-' or a space, then you have an array of possibly 3 strings.
So, you look at the last character, if it is a single quote, then multiply that by 12.
If a double quote, then split on '/' and just calculate the fraction, and for a number that is neither of these it is an inch, just add it to the total.
This way you don't assume the order or what if you just have fractional inches.
Just loop through the array and then go through the algorithm above, so if someone did
3'-4'-4/2" then you can calculate it easily.
UPDATE:
I am adding code based on the comment from the OP.
You may want to refer to this to get more ideas about split.
http://www.java-examples.com/java-string-split-example
But, basically, just do something like this (not tested, just written out):
public double convertArchToDecimal(String instr, String delimiter) {
String[] s = instr.split(delimiter);
int ret = 0;
for(int t = 0; t < s.length; t++) {
char c = s[t].charAt(s[t] - length);
switch(c) {
case '\'': //escape single quote
String b = s[t].substring(0, s[t].length - 1).split("/");
try {
ret += Integer.parse(s[t].trim()) * 12;
} catch(Exception e) { // Should just need to catch if the parse throws an error
}
break;
case '"': // may need to escape the double quote
String b = s[t].substring(0, s[t].length - 1).split("/");
int f = 0;
int g = 0;
try {
f = Integer.parse(b[0]);
g = Integer.parse(b[1]);
ret += f/g;
} catch(Exception e) {
}
break;
default:
try {
ret += Integer.parse(s[t].trim());
} catch(Exception e) { // Should just need to catch if the parse throws an error
}
break;
}
}
return ret;
}
I am catching more exceptions than is needed, and you may want to use the trim() method more than I did, to strip whitespace before parsing, to protect against 3 / 5 " for example.
By passing in a space or dash it should suffice for your needs.
You may also want to round to some significant figures otherwise rounding may cause problems for you later.

Categories

Resources