My current goal is to parse fractions and create improper fractions.
For example:
1_1/3 + 5/3
should come into the console as
4/3 + 5/3
Could someone tell me am I going in the right direction and what should I be focusing on?
import java.util.Scanner;
public class FracCalc {
public static void main (String[] args) {
Scanner input = new Scanner(System.in);
System.out.println("Welcome to FracCalc");
System.out.println("Type expressions with fractions, and I will evaluate them.");
boolean isTrue = true;
String in = "";
while(isTrue) {
in = input.nextLine();
if (in.equals("quit")) {
System.out.println("Thanks for running FracCalc!");
isTrue = false;
}else{
System.out.println("You asked me to compute" + in);
}
}
}
public static void parse(String in){
int underscore = in.indexOf("_");
int slash = in.lastIndexOf("/");
String wholenumber = in.substring(0, underscore);
String numerator = in.substring(underscore + 1,slash);
String denominator = in.substring(slash + 1);
if (underscore<0 & slash<0) {
in = wholenumber;
} else if (underscore<0 & slash>0) {
in = in;
} else if (underscore>0 & slash>0) {
} else if (underscore>0 & slash<0) {
in = "Error";
}
}
}
I'd say you're definitely on the right track although I'd consider a bit of a different approach to your parsing.
I would parse the string character by character. Iterate through the string and if your current character is a number, append it to a StringBuffer called "currentNumber" or something. If your current character is not a number you need to decide what to do. If it's an underscore, you know that the value in your currentNumber variable is the whole number part. You could then store that in a separate variable and clear your currentNumber buffer. If your current character is a slash character, you'd know that the value in currentNumber is the numerator of your fraction. If the current character is a space character you can probably just ignore it. If it is a '+' or '-', you'll know that what you have in your currentNumber variable is your fraction denominator. You should then also store the symbol in a separate variable as your "operator". There are numerous ways you could implement this. For example you could have logic that said: "if I have a valid value in my numerator and not in my denominator and the character I'm currently looking at is not a valid numeric character, then I have appended all the digits in my denominator to the currentNumber variable and it should therefore now contain my denominator. So put the value in currentNumber into my denominator variable and move on to the next character".
I hope I haven't lost you completely here... but of course this may be a bit too advanced for what you need to do. For example, you didn't specify the format of the input string, will it always be in the exact same format as you mentioned or can it look different? Can the whole number part have two digits or can it be skipped alltogether?
The method I described above is called a finite state machine and if you haven't learnt about them yet your teacher should probably be impressed if you handed in an assignment using this technique. There is a lot of reading material on FSM so Google is your friend.
But just to be clear. Your solution looks like it would work too, it just probably won't be as "dynamic".
Related
I am building a basic calculator in Java and have a few requirements to meet for it. it takes a math expression input from the user example. 3 * 5 ^ 5 (must be separated by spaces).
I'm having trouble figuring out how to pass the basic math expression input string math to the isNumber function and then in that function checking the first [0] spot of the string and every 4th spot (since spaces are still in there?) after for a double. I can do it if I turn math into a string array, but the requirements specifically said I cannot turn string math into an array until afterwards. I know if I can figure this out, then it shouldn't be hard to make an operator validation function and do the same for the spots of the input...
here is my current progress on the program.
import java.util.Scanner;
/**
*
* #author
*/
public class Calculator2 {
static ArrayList<String> validOperators = new ArrayList<String>(){{
add("^");
add("*");
add("/");
add("+");
add("-");
}};
public static void main(String[] args) {
System.out.println("This is a text based calculator!");
Scanner in = new Scanner(System.in);
boolean loop = true;
while (loop) {
System.out.println("Enter a math expression ot type quit to exit: ");
String math = in.nextLine();
if ("quit".equalsIgnoreCase(math)) {
System.out.print("Quitting");
break;
}
if (isOperator(math)){
if (isNumber(math)){
String[] splitExpression = math.split("\\s+");
if(isValidExpression(splitExpression)){
for (int i=0; i<splitExpression.length; i++){
System.out.println(splitExpression[i]);
}
System.out.println("Number of tokens: " + splitExpression.length);
}
}else {
System.out.println("invalid expression!");
}
}else{
System.out.println("please use valid operators");
}
}
}
public static boolean isNumber(String number){
return
}
} ```
Numbers can be variable length, there can be multiple spaces - your approach (which involves things like 'check the 4th character') cannot work - you cannot work in absolute positions like this. It must be relative.
The usual approach is to realize that you've constructed an actual grammar here, and it can get quite complicated (toss in the ability to write parentheses and it's quite complicated indeed). Seems simple, but it just isn't.
Generally, you FIRST tokenize, which turns your stream of characters, into a stream of nodes. + is a node. So is 1.21398123. Nodes know what kind of thing they represent.
Then, you turn the stream of nodes into a tree. Then you calculate the result by going through the tree, from the leaves all the way up to the root.
i,e, this:
"10 * (2+3)"
is first turned into:
List.of(
NumericNode.of(10),
Operator.MULTIPLY,
Operator.OPEN_PAREN,
NumericNode.of(2),
Operator.ADD,
NumericNode.of(3),
Operator.CLOSE_PAREN);
Then that is turned into:
*
/ \
10 +
/ \
2 3
And that you can then trivially 'resolve' into 50 by collapsing nodes recursively.
As you can probably tell once you break it down like this: Not trivial.
You can search the web for tokenizers and parser tech on how to do this job. It'll take some reading.
I am trying to get this code to run and basically solve an equation. So, I asked the user to write an equation. It looked like this:
System.out.println("Write an equation and I will solve for x.");
int answer = in.nextLine();
But I can't get the user to write a string and an int. Do I need to say String answer or int answer?
An int is used when you want the user to enter a number, but here you're looking for a combination of numbers and other characters, so you will need to use a string. When you have the equation stored in a string, you can use other methods to split up the equation into something solvable, then set int answer to whatever the answer comes out to be.
On a simpler side, String will be required input from the user, User will enter the equation.
Then comes the complex part of solving/computing the equation.
1.) create your own parser to pass operands/operator.
2.) Provide a equation with values to some API, you can make use of MVEL or ANTLR
Here's a little program that demonstrates one way to get the equation and divide into numeric / non-numeric values provided the equation input is space delimited. You can then determine what the non-numeric values are and proceed from there.
import java.util.Scanner;
public class SolveX{
public static void main(String[] a){
Scanner in = new Scanner(System.in);
System.out.println("Write an equation and I will solve for x.");
String input = "";
while( in.hasNext() ){
input = in.next();
try{
double d = Double.parseDouble(input);
System.out.println("Double found at: " + input);
// Do what you need to with the numeric value
}
catch(NumberFormatException nfe){
System.out.println("No double found at: " + input);
// Do what you need to with the non numeric value
}
}
}//end main
}//end SolveX class
I am working on a program that takes in 2 numbers and either adds, subtracts, multiplies, or divides them. The numbers can either be binary, hexadecimal, octal, or decimal numbers. In order for a user of the program to enter a binary number they must enter a "0b" in front of it. They would need to enter a "0" in front of the octal numbers, "0x" for hexadecimal, and just the number for a decimal number. The original number that is read in is a String then the method below converts it to an int or a double. I am trying to find out a solution if a user enters in a "0" for the number itself. Is there a way to see if the users input is only a 0 with nothing preceding it or following it? Here is my method I am working with. Any help would be awesome!
public double evaluate()
{
int sign = getSign();//makes number positive or negative
if (getOperand().startsWith("0"))// this is where i am trying to see if the number is just 0
{
return 0 * sign;
}
else if (getOperand().startsWith("0x"))
{
String op = getOperand().substring(2);
return Integer.parseInt(op, 16)*sign;
}
else if (getOperand().startsWith("0b"))
{
String op = getOperand().substring(2);
return Integer.parseInt(op, 2)*sign;
}
else if (getOperand().startsWith("0"))
{
String op = getOperand().substring(1);
return Integer.parseInt(op, 8)*sign;
}
else
{
String op = getOperand();
return (Double.parseDouble(op)) * sign;
}
You're making more work for yourself than you need. Just parse plain "0" as an octal number -- the result is still 0. No need to remove the leading zero.
That is,
// ...
else if (getOperand().startsWith("0"))
{
String op = getOperand();
return Integer.parseInt(op, 8)*sign;
}
// ...
Simply do this:
getOperand().equals("0")
If you want to check that the string is actually a zero with nothing before or after, you want equality.
getOperand().equals("0")
You can always check
if (getOperand().equals("0"))
However, you have another problem - your code will throw exceptions for invalid inputs. If the user enters just the prefix "0b" or "0x", your substring call would throw an exception. You must verify that there's at least one character following the prefix. It will also throw an exception if the substring can't be parsed as a number of the requested base.
I am working on a class assignment this morning and I want to try and solve a problem I have noticed in all of my team mates programs so far; the fact that spaces in an int/float/double cause Java to freak out.
To solve this issue I had a very crazy idea but it does work under certain circumstances. However the problem is that is does not always work and I cannot figure out why. Here is my "main" method:
import java.util.Scanner; //needed for scanner class
public class Test2
{
public static void main(String[] args)
{
BugChecking bc = new BugChecking();
String i;
double i2 = 0;
Scanner in = new Scanner(System.in);
System.out.println("Please enter a positive integer");
while (i2 <= 0.0)
{
i = in.nextLine();
i = bc.deleteSpaces(i);
//cast back to float
i2 = Double.parseDouble(i);
if (i2 <= 0.0)
{
System.out.println("Please enter a number greater than 0.");
}
}
in.close();
System.out.println(i2);
}
}
So here is the class, note that I am working with floats but I made it so that it can be used for any type so long as it can be cast to a string:
public class BugChecking
{
BugChecking()
{
}
public String deleteSpaces(String s)
{
//convert string into a char array
char[] cArray = s.toCharArray();
//now use for loop to find and remove spaces
for (i3 = 0; i3 < cArray.length; i3++)
{
if ((Character.isWhitespace(cArray[i3])) && (i3 != cArray.length)) //If current element contains a space remove it via overwrite
{
for (i4 = i3; i4 < cArray.length-1;i4++)
{
//move array elements over by one element
storage1 = cArray[i4+1];
cArray[i4] = storage1;
}
}
}
s = new String(cArray);
return s;
}
int i3; //for iteration
int i4; //for iteration
char storage1; //for storage
}
Now, the goal is to remove spaces from the array in order to fix the problem stated at the beginning of the post and from what I can tell this code should achieve that and it does, but only when the first character of an input is the space.
For example, if I input " 2.0332" the output is "2.0332".
However if I input "2.03 445 " the output is "2.03" and the rest gets lost somewhere.
This second example is what I am trying to figure out how to fix.
EDIT:
David's suggestion below was able to fix the problem. Bypassed sending an int. Send it directly as a string then convert (I always heard this described as casting) to desired variable type. Corrected code put in place above in the Main method.
A little side note, if you plan on using this even though replace is much easier, be sure to add an && check to the if statement in deleteSpaces to make sure that the if statement only executes if you are not on the final array element of cArray. If you pass the last element value via i3 to the next for loop which sets i4 to the value of i3 it will trigger an OutOfBounds error I think since it will only check up to the last element - 1.
If you'd like to get rid of all white spaces inbetween a String use replaceAll(String regex,String replacement) or replace(char oldChar, char newChar):
String sBefore = "2.03 445 ";
String sAfter = sBefore.replaceAll("\\s+", "");//replace white space and tabs
//String sAfter = sBefore.replace(' ', '');//replace white space only
double i = 0;
try {
i = Double.parseDouble(sAfter);//parse to integer
} catch (NumberFormatException nfe) {
nfe.printStackTrace();
}
System.out.println(i);//2.03445
UPDATE:
Looking at your code snippet the problem might be that you read it directly as a float/int/double (thus entering a whitespace stops the nextFloat()) rather read the input as a String using nextLine(), delete the white spaces then attempt to convert it to the appropriate format.
This seems to work fine for me:
public static void main(String[] args) {
//bugChecking bc = new bugChecking();
float i = 0.0f;
String tmp = "";
Scanner in = new Scanner(System.in);
System.out.println("Please enter a positive integer");
while (true) {
tmp = in.nextLine();//read line
tmp = tmp.replaceAll("\\s+", "");//get rid of spaces
if (tmp.isEmpty()) {//wrong input
System.err.println("Please enter a number greater than 0.");
} else {//correct input
try{//attempt to convert sring to float
i = new Float(tmp);
}catch(NumberFormatException nfe) {
System.err.println(nfe.getMessage());
}
System.out.println(i);
break;//got correct input halt loop
}
}
in.close();
}
EDIT:
as a side note please start all class names with a capital letter i.e bugChecking class should be BugChecking the same applies for test2 class it should be Test2
String objects have methods on them that allow you to do this kind of thing. The one you want in particular is String.replace. This pretty much does what you're trying to do for you.
String input = " 2.03 445 ";
input = input.replace(" ", ""); // "2.03445"
You could also use regular expressions to replace more than just spaces. For example, to get rid of everything that isn't a digit or a period:
String input = "123,232 . 03 445 ";
input = input.replaceAll("[^\\d.]", ""); // "123232.03445"
This will replace any non-digit, non-period character so that you're left with only those characters in the input. See the javadocs for Pattern to learn a bit about regular expressions, or search for one of the many tutorials available online.
Edit: One other remark, String.trim will remove all whitespace from the beginning and end of your string to turn " 2.0332" into "2.0332":
String input = " 2.0332 ";
input = input.trim(); // "2.0332"
Edit 2: With your update, I see the problem now. Scanner.nextFloat is what's breaking on the space. If you change your code to use Scanner.nextLine like so:
while (i <= 0) {
String input = in.nextLine();
input = input.replaceAll("[^\\d.]", "");
float i = Float.parseFloat(input);
if (i <= 0.0f) {
System.out.println("Please enter a number greater than 0.");
}
System.out.println(i);
}
That code will properly accept you entering things like "123,232 . 03 445". Use any of the solutions in place of my replaceAll and it will work.
Scanner.nextFloat will split your input automatically based on whitespace. Scanner can take a delimiter when you construct it (for example, new Scanner(System.in, ",./ ") will delimit on ,, ., /, and )" The default constructor, new Scanner(System.in), automatically delimits based on whitespace.
I guess you're using the first argument from you main method. If you main method looks somehow like this:
public static void main(String[] args){
System.out.println(deleteSpaces(args[0]);
}
Your problem is, that spaces separate the arguments that get handed to your main method. So running you class like this:
java MyNumberConverter 22.2 33
The first argument arg[0] is "22.2" and the second arg[1] "33"
But like other have suggested, String.replace is a better way of doing this anyway.
I am trying to get java to display the middle digit of a 1-4 digit integer, and if the integer has an even number of digits i would get it to display that there is no middle digit.
I can get the program to take get the integer from the user but am pretty clueless as how to get it to pick out the middle digit or differentiate between different lengths of integer.
thanks
Hint: Convert the integer to a String.
Java int to String - Integer.toString(i) vs new Integer(i).toString()
You may also find the methods String.length and String.charAt useful.
This sounds like it might be homework, so I will stay away from giving an exact answer. This is much more about how to display characters than it is about integers. Think about how you might do this if the questions was to display the middle letter of a word.
Something like this?
import java.util.Scanner;
public class Main {
public static void main(String args[]) {
Scanner s = new Scanner(System.in);
System.out.print("Enter an integer: ");
while (!s.hasNextInt()) {
s.next();
System.out.println("Please enter an integer.");
}
String intStr = "" + s.nextInt();
int len = intStr.length();
if (len % 2 == 0)
System.out.println("Integer has even number of digits.");
else
System.out.println("Middle digit: " + intStr.charAt(len / 2));
}
}
Uhm, I realized I might just have done someones homework... :-/ I usually try to avoid it. I'll blame the OP for not being clear in this case