The user enters an array of numbers such as "123456789"
and then the user is supposed to enter a string of commands such as "PE"
and my program will check each character in the string.
P = Remove the last number entered, which is 9
E = Prints out the final result.
To this point everything was working fine.
But my problem is that I have to be able to read the command when the user inputs "P(any number)", and I have to place that number at the end of the array of numbers.
So if it was P(4), the result would be "1234567894".
How can I do this ?
This is what I have right now for P and E.
if (commandList.get(x).equals("P(")) {
JOptionPane.showMessageDialog(null, "HI");
}
else if (commandList.get(x).equals("P")) {
strList.remove(strList.size()-1);
x++;
}
As far as I understand, your problem is to extract the 'digit' from the string "P(digit)" ?
Well you have to parse the input string, e.g., by searching for bounding characters, here '(' and ')'. For example by something like that:
String s = "P(3)";
String number = s.substring(s.indexOf("(") + 1, s.indexOf(")"));
strList.append(number);
But this would also accept anything within the bracktes, e.g., "foooo" from "P(foooo)", and it would crash if ')' cannot be found, e.g., s = "P(123", and it would accept "P(3)blah54" which is strictly spoken invalid. To improve your parser, you can use regular expressions, e.g., to check if the input is exactly of the form "P(2)" for exactly a single digit, you can use
String s = "P(3)";
if (!s.matches("P\\(\\d\\)"))
throw new RuntimeException("invalid input format: " + s);
String number = s.substring(s.indexOf("(") + 1, s.indexOf(")"));
strList.append(number);
If you explicitly want to cast the digit to an int, you might have a look at Integer.parseInt(...), e.g.,
int i = Integer.parseInt(number);
Related
I am working on an exercise with the following criteria:
"The input consists of pairs of tokens where each pair begins with the type of ticket that the person bought ("coach", "firstclass", or "discount", case-sensitively) and is followed by the number of miles of the flight."
The list can be paired -- coach 1500 firstclass 2000 discount 900 coach 3500 -- and this currently works great. However, when the String and int value are split like so:
firstclass 5000 coach 1500 coach
100 firstclass
2000 discount 300
it breaks entirely. I am almost certain that it has something to do with me using this format (not full)
while(fileScanner.hasNextLine())
{
StringTokenizer token = new StringTokenizer(fileScanner.nextLine(), " ")
while(token.hasMoreTokens())
{
String ticketClass = token.nextToken().toLowerCase();
int count = Integer.parseInt(token.nextToken());
...
}
}
because it will always read the first value as a String and the second value as an integer. I am very lost on how to keep track of one or the other while going to read the next line. Any help is truly appreciated.
Similar (I think) problems:
Efficient reading/writing of key/value pairs to file in Java
Java-Read pairs of large numbers from file and represent them with linked list, get the sum and product of each pair
Reading multiple values in multiple lines from file (Java)
If you can afford to read the text file in all at once as a very long String, simply use the built-in String.split() with the regex \\s+, like so
String[] tokens = fileAsString.split("\\s+");
This will split the input file into tokens, assuming the tokens are separated by one or more whitespace characters (a whitespace character covers newline, space, tab, and carriage return). Even and odd tokens are ticket types and mile counts, respectively.
If you absolutely have to read in line-by-line and use StringTokenizer, a solution is to count number of tokens in the last line. If this number is odd, the first token in the current line would be of a different type of the first token in the last line. Once knowing the starting type of the current line, simply alternating types from there.
int tokenCount = 0;
boolean startingType = true; // true for String, false for integer
boolean currentType;
while(fileScanner.hasNextLine())
{
StringTokenizer token = new StringTokenizer(fileScanner.nextLine(), " ");
startingType = startingType ^ (tokenCount % 2 == 1); // if tokenCount is odd, the XOR ^ operator will flip the starting type of this line
tokenCount = 0;
while(token.hasMoreTokens())
{
tokenCount++;
currentType = startingType ^ (tokenCount % 2 == 0); // alternating between types in current line
if (currentType) {
String ticketClass = token.nextToken().toLowerCase();
// do something with ticketClass here
} else {
int mileCount = Integer.parseInt(token.nextToken());
// do something with mileCount here
}
...
}
}
I found another way to do this problem without using either the StringTokenizer or the regex...admittedly I had trouble with the regular expressions haha.
I declare these outside of the try-catch block because I want to use them in both my finally statement and return the points:
int points = 0;
ArrayList<String> classNames = new ArrayList<>();
ArrayList<Integer> classTickets = new ArrayList<>();
Then inside my try-statement, I declare the index variable because I won't need that outside of this block. That variable increases each time a new element is read. Odd elements are read as ticket classes and even elements are read as ticket prices:
try
{
int index = 0;
// read till the file is empty
while(fileScanner.hasNext())
{
// first entry is the ticket type
if(index % 2 == 0)
classNames.add(fileScanner.next());
// second entry is the number of points
else
classTickets.add(Integer.parseInt(fileScanner.next()));
index++;
}
}
You can either catch it here like this or use throws NoSuchElementException in your method declaration -- As long as you catch it on your method call
catch(NoSuchElementException noElement)
{
System.out.println("<###-NoSuchElementException-###>");
}
Then down here, loop through the number of elements. See which flight class it is and multiply the ticket count respectively and return the points outside of the block:
finally
{
for(int i = 0; i < classNames.size(); i++)
{
switch(classNames.get(i).toLowerCase())
{
case "firstclass": // 2 points for first
points += 2 * classTickets.get(i);
break;
case "coach": // 1 point for coach
points += classTickets.get(i);
break;
default:
// budget gets nothing
}
}
}
return points;
The regex seems like the most convenient way, but this was more intuitive to me for some reason. Either way, I hope the variety will help out.
simply use the built-in String.split() - #bui
I was finally able to wrap my head around regular expressions, but \s+ was not being recognized for some reason. It kept giving me this error message:
Invalid escape sequence (valid ones are \b \t \n \f \r " ' \ )Java(1610612990)
So when I went through with those characters instead, I was able to write this:
int points = 0, multiplier = 0, tracker = 0;
while(fileScanner.hasNext())
{
String read = fileScanner.next().split(
"[\b \t \n \f \r \" \' \\ ]")[0];
if(tracker % 2 == 0)
{
if(read.toLowerCase().equals("firstclass"))
multiplier = 2;
else if(read.toLowerCase().equals("coach"))
multiplier = 1;
else
multiplier = 0;
}else
{
points += multiplier * Integer.parseInt(read);
}
tracker++;
}
This code goes one entry at a time instead of reading a whole array void of whitespace as a work-around for that error message I was getting. If you could show me what the code would look like with String[] tokens = fileAsString.split("\s+"); instead I would really appreciate it :)
you need to add another "\" before "\s" to escape the slash before "s" itself – #bui
So for school I need to make a GUI calculator, I have fully made the calculator working, but only up to single digit arthmatic (1+1) but now I wish to make it that that I can have multiple digits inputed (123 + 45) this is my code:
b1.addActionListener(e -> {System.out.println("Response:1 was inputed onto calculator");
if(arth == "") {
num1S = Double.toString(num1);
Tnum1S = "1" + num1S;
num1 = Double.parseDouble(Tnum1S);
l.setText(Tnum1S);
Tnum1S = "";
} else {
num2S = Double.toString(num2);
Tnum2S = num2S + "1";
num2 = Double.parseDouble(Tnum2S);
l.setText(Tnum2S);
Tnum2S = "";
}});
//T at the start means Temporary, S at te end means a String, normally my numbers are set to double.
This is a screenshot of my results from my try of making this work does anyone know how to make it that the number is not added into the decimal places?
Maybe this is what you want:
DecimalFormat format = new DecimalFormat("#.#"); // you can change it here
System.out.println(format.format(d));
If you take a look at the line Tnum1S = "1" + num1S; , you are essentially concatenating 1 to the content of num1S as a String. Instead, for building a calculator you should be adding them as doubles and then push to the user interface.
num1S contains the String equivalent of num1.
num1S = Double.toString(num1);
Tnum1S now gets a 1 concatenated with num1S.
Tnum1S = "1" + num1S;
You are now converting the concatenated value ( not added value )back to Double
num1 = Double.parseDouble(Tnum1S);
You are finally setting it on the UI.
l.setText(Tnum1S);
Instead you should,
Convert the numbers of your interest from String to Double.
Perform the operation as a Double.
Push the result back to the user interface as a String.
In short, in your case, you are using the concatenation operation on String rather than the addition operation on a double.
Thanks for checking out my question.
Starting off, the program has the following goal; the user inputs currency formatted as "xD xC xP xH"; the program checks the input is correct and then prints back the 'long' version: "x Dollars, x Cents, x Penny's, x half penny's"
Here I have some code that takes input from user as String currencyIn, splits the string into array tokens, then replaces the D's with Dollars etc and prints the output.
public class parseArray
{
public parseArray()
{
System.out.print('\u000c');
String CurrencyFormat = "xD xS xP xH";
System.out.println("Please enter currency in the following format: \""+CurrencyFormat+"\" where x is any integer");
System.out.println("\nPlease take care to use the correct spacing enter the exact integer plus type of coin\n\n");
Scanner input = new Scanner(System.in);
String currencyIn = input.nextLine();
currencyIn.toUpperCase();
System.out.println("This is the currency you entered: "+currencyIn);
String[] tokens = currencyIn.split(" ");
for (String t : tokens)
{
System.out.println(t);
}
String dollars = tokens[0].replaceAll("D", " Dollars ");
String cents = tokens[1].replaceAll("C", " cents");
String penny = tokens[2].replaceAll("P", " Penny's");
String hPenny = tokens[3].replaceAll("H", " Half penny's");
System.out.println(" "+dollars+ " " +cents+ " " +penny+ " " +hPenny);
input.close();
}
}
Question 1: At the moment the program prints out pretty anything you put in. how do I establish some input control? I've seen this done in textbooks with switch statement and a series of if statements, but were too complicated for me. Would it parse characters using charAt() for each element of the array?
Question 2: Is there a 'better' way to print the output? My friend said converting my 4 strings (dollars, cents, penny's, hpenny's) into elements 0, 1, 2, 3 of a new array (called newArray) and print like this:
System.out.println(Arrays.toString(newArray));
Many thanks in advance.
There is a neat solution, involving Regular Expressions, Streams and some lambdas. Core concept is that we define the input format through a regular expression. We need some sequence of digits, followed by a 'D' or a 'd', followed by a " ", followed by a sequence of digits, followed by a C or c,... I will skip derivation of this pattern, it is explained in the regular expression tutorial I linked above. We will find that
final String regex = "([0-9]+)[D|d]\\ ([0-9]+)[C|c]\\ ([0-9]+)[P|p]\\ ([0-9]+)[H|h]";
satisfies our needs. With this regular expression we can now determine whether our input String has the right format (input.matches(regex)), as well as extract the bits of information we are actually interested in (input.replaceAll(regex, "$1 $2 $3 $4"). Sadly, replaceAll yields another String, but it will contain the four digit sequences we are interested in, divided by a " ". We will use some stream-magic to transform this String into a long[] (where the first cell holds the D-value, the second holds the C-value,...). The final program looks like this:
import java.util.Arrays;
public class Test {
public static void main(String... args) {
final String input = args[0];
final String regex =
"([0-9]+)[D|d]\\ ([0-9]+)[C|c]\\ ([0-9]+)[P|p]\\ ([0-9]+)[H|h]";
if (input.matches(regex) == false) {
throw new IllegalArgumentException("Input is malformed.");
}
long[] values = Arrays.stream(input.replaceAll(regex, "$1 $2 $3 $4").split(" "))
.mapToLong(Long::parseLong)
.toArray();
System.out.println(Arrays.toString(values));
}
}
If you want to have a List<Long> instead a long[] (or a List<Integer> instead of an int[]), you would use
List<Long> values = Arrays.stream(input.replaceAll(regex, "$1 $2 $3 $4").split(" "))
.map(Long::parseLong)
.collect(Collectors.toList());
It is necessary to change mapToLong to map to receive a Stream<Long> instead of a LongStream. I am sure that one could somehow write a custom Collector for LongStream to transform it into a List<Long>, but I found this solution more readable and reliable (after all, the Collector used comes from Oracle, I trust they test their code extensively).
Here is some example call:
$> java Test "10D 9c 8p 7H"
[10, 9, 8, 7]
$> java Test "10E 9C 8P 7H"
Exception in thread "main" java.lang.IllegalArgumentException: Input is malformed.
at Test.main(Test.java:10)
$> java Test "10D 9C 8P 7H 10D 9C 8P 7H"
Exception in thread "main" java.lang.IllegalArgumentException: Input is malformed.
at Test.main(Test.java:10)
Question1
You can actually check if the input is what it's supposed to be with simple checks. For example, you can check the first element like this:
if(tokens[0].charAt(1).equals("D"))
return true;
else
return false;
Another way to check if the input is correct is by using Regular Expressions, but I assume you are a beginner and this is too much trouble for you, although it is the better way. So I leave it to you to look through it later.
Question2
You can actually listen to your friend and do as they said. You can write it as follows:
for(int i = 0; i < 4; i++)
System.out.print(" " + tokens[i])
System.out.println();
Or you may use
System.out.println(Arrays.toString(newArray));
And you have saved newArray like this:
newArray[0] = " " + tokens[0];
you could use the .equals() method to see if what a user has typed in matches what you have
if (currencyIn.equals("CurrencyFormat"))
{
...
}
this is probably the simplest way i can think of!
so in my program the user has to register and one of the fields to enter is the phone number.
I want to check if the first 3 numbers they enter is valid or not
if (TextUtils.isEmpty(PhoneNumber) || PhoneNumber != "055, 050, 056, 052") {
PhoneNumber.setError("Please enter a valid phone number")
return;`
}
this is my code but it set off so many errors, can somebody please help me with this?
PhoneNumber != "055, 050, 056, 052" is wrong.
You can create a string array and store them there.
String okNums = {"055", "050", "056", "052"};
and then check if the phone number is valid
if (TextUtils.isEmpty(PhoneNumber) ||
!Arrays.asList(okNums ).contains(PhoneNumber)) {
PhoneNumber.setError("Please enter a valid phone number")
return;`
}
turn your pattern into an array and search if the phone is beginning with any of those
String d = "055, 050, 056, 052";
String p = "055 66";
String[] pArr = d.split(",");
for (String patt : pArr ) {
System.out.println(patt.trim());
System.out.println(p.indexOf(patt)==0);
}
//Get the string from the edit text by:
String number = yourEditText.getText().toString();
if(number != null && number.matches("639[0-9]{9}"))
//do what you need to do for valid input
else
//do what you need to do for invalid input
matches() ensures that the entire string cooresponds (exactly) to the regular expression that it takes. 639[0-9]{9} says that the string must start off with 639 and then be followed by exactly 9 digits (0-9). If you wanted to match "639" followed by 7 to 9 numbers, for example, you would use: 639[0-9]{7,9}. Regular expressions:
A simple solution would be .startsWith()
if (!PhoneNumber.startsWith("055") || !PhoneNumber.startsWith("050") || !PhoneNumber.startsWith("056") || !PhoneNumber.startsWith("052")) {
// does not match
}
Another option is to use a regex for this
if (!PhoneNumber.matches("^(055|050|056|052)\d+$")){
// does not match
}
The worst thing you had done is, your comparison. You can't compare like this, when you need to compare with several values. Instead you have to use something like List#contains method to check whether your PhoneNumber or not.
String[] check = {"055", "050", "056", "052" };
if (TextUtils.isEmpty(PhoneNumber) || Arrays.asList(check).contains(PhoneNumber.getText().toString())) {
PhoneNumber.setError("Please enter a valid phone number")
return;
}
Alright so from what I understood here is a solution, if the phone number has is a one full string you can extract the first 3 numbers using this:
String s="052487978";
String ex = s.substring(0,3));//052
Create a int array and store all the valid options in there
int[] array = {055, 050, 056, 052}; and covert the string ex to int int value = Integer.parseInt(ex); and check if its available in the string that contains valid options.
boolean contains = IntStream.of(array ).anyMatch(x -> x == value);
If it is true its valid and if its false its invalid.
Wrote a method which takes in a String and checks to see the follow conditions:
If String is "quit", it will terminate the program.
If the String is any value other than an integer, it should return "Invalid input ".
Any negative integers and also 0 should return "Invalid input".
However, when I passed in 10, it returned as "Invalid input"?
Please advise:
public static String validate(String input) {
Pattern pattern = Pattern.compile(".*[^1-9].*");
StringBuilder results = new StringBuilder();
if (input.equals("quit")) {
System.exit(1);
} else if (!pattern.matcher(input).matches() == false) {
results.append("Invalid input ");
results.append("'");
results.append(input);
results.append("'");
}
return results.toString();
}
What's wrong with what I am doing?
You should write a pattern of what you expect instead of what you're not.
As describe what you want is always simpler that describe the rest of it.
So you expect :
Pattern acceptPattern = Pattern.compile("[1-9][0-9]*");
You may consider make you conditional expression simpler and correct by not using both ! and == false at the same time:
Which will make :
if (!acceptPattern .matcher(input).matches()) {//Invalid input code}
or
if (acceptPattern .matcher(input).matches() == false) {//Invalid input code}
note :
You write if(!A == false) => if(A == true) => if(A) but which was the inverse
It looks like you want to match one or more digits, where the first one is not a zero.
[1-9]\d*
If you want to force it to be the entire string, you can add anchors, like this:
^[1-9]\d*$
Your regex string doesn't allow for the presence of a zero (not just a lone zero).
That is, the string ".*[^1-9].*" is looking for "any number of characters, something that isn't 1-9, and any number of characters". When it finds the zero, it gives you your incorrect result.
Check out What is the regex for "Any positive integer, excluding 0" for how to change this.
Probably the most helpful solution on that page is the regex [0-9]*[1-9][0-9]* (for a valid integer). This allows for leading zeros and/or internal zeros, both of which could be present in a valid integer. In using Matcher#matches you also ensure that this regex matches the whole input, not just part of it (without the need to add in beginning and end anchors -- ^$).
Also, the line else if (!pattern.matcher(input).matches() == false) could be made a lot more clear.... maybe try else if (pattern.matcher(input).matches()) instead?