Issue with Reading two Int values from a file - java

I have file with the below data
A,8,43
B,7,42,
C,9,34
I am using the below code to read the data
Scanner input = new Scanner(new File("D:\\test.txt"));
input.useDelimiter(",|\n");
while(input.hasNext()) {
String name = input.next();
int age = input.nextInt();
int height = input.nextInt();
When I am executing the program I am getting InputMisMatch exception,
Please suggest what is mistake.

At end of second line you have , and line separator (I am assuming \n) This means you have empty element between these two delimiters.
So in third iteration
String name = input.next();
int age = input.nextInt();
int height = input.nextInt();
input.next(); is consuming "", which means input.nextInt() will try to consume C.
To solve this problem you can set delimiter to be combination of one or more commas and line separators like
input.useDelimiter("(,|\n)+");
To improve your code even farther instead of \n you can use \\R added in Java 8 (or \r|\n in earlier versions) to handle all line separators, because currently you don't consider \r as delimiter so it can be treated as valid token.
So better solution would be using
input.useDelimiter("(,|\\R)+"); //for readability
or even
input.useDelimiter("[,\r\n]+");

The problem lies at the use of the useDelimiter method. This method accepts a regular expression as a parameter. You can't just say ,|\n to mean "comma or new line". There are rules.
What you should pass in is "[,\\n]+". This means "one or more characters in the following set: [comma, new line character]".
With the regex that you are passing currently, ,|\n, it means that the delimiter should be either , or \n, but not both. So when it encounters the second line:
B,7,42,
this is what happens:
next reads "B"
nextInt reads "7"
nextInt reads "42"
next reads an empty string that is between the "," and the new line.
nextInt now tries to read the next token "C", which it can't.
EXCEPTION!

I would do things differently -- use one Scanner to parse each line of the File and use a 2nd Scanner nested within the while loop to extract tokens or data from the lines obtained from the first Scanner. For example:
String filePath = "D:\\test.txt";
File file = new File(filePath);
// use try-with-resources
try (Scanner input = new Scanner(file)) {
while (input.hasNextLine()) {
String line = input.nextLine();
Scanner lineScanner = new Scanner(line);
lineScanner.useDelimiter("\\s*,\\s*"); // get comma and any surrounding whitespace if present
String name = "";
int age = 0;
int height = 0;
if (lineScanner.hasNext()) {
name = lineScanner.next();
} // else ... throw exception?
if (lineScanner.hasNextInt()) {
age = lineScanner.nextInt();
} // else ... throw exception?
if (lineScanner.hasNextInt()) {
height = lineScanner.nextInt();
} // else ... throw exception?
// use name, age, height here
System.out.printf("%s %s %s%n", name, age, height);
lineScanner.close(); // don't waste resources -- return them
}
} catch (IOException e) {
e.printStackTrace();
}

Related

Java .split() by character with spaces in string [duplicate]

This question already has answers here:
What's the difference between next() and nextLine() methods from Scanner class?
(15 answers)
Closed 5 years ago.
I am trying to read a line from a text file in java. I get a java.lang.ArrayIndexOutOfBoundsException: 1 exception.
Here is my code:
try {
Scanner kb = new Scanner(new FileReader(fileName));
String line = "";
int count = 0;
while (kb.hasNext()) {
line = kb.next();
String[] temp = line.split("#");
System.out.println(temp[1]);
Wedding tempWed = new Wedding(temp[0], temp[1], temp[2], temp[3], Integer.parseInt(temp[4]));
test[count] = tempWed;
count++;
}
} catch (FileNotFoundException ex) {
}
This is the line in the textfile:
Chiquita Sanford#Magee Sosa#2016-11-05#Garden#84
I need to split by the "#", and this partly works.
Java throws the exception when I try to access the element at position 1.
I think this is because there is a space between the first name and the surname, because when I System.out.println(temp[0]) it displays "Chiquita" and not "Chiquita Sanford".
Does Java have some restriction on splitting when there are multiple words in the first array index.
You have to use the nextLine method to read the full line. next will read until the first token ("Chiquita" in your case because its followed by a space character and is interpreted as a delimiter). So change this line:
line = kb.next();
with this:
line = kb.nextLine();
You are using kb.next() that will return the next word not the next line, for this use kb.nextLine() similar issue with kb.hasNext() needs to be kb.hasNextLine()

Java - Scanner.nextLine() skipping even when accounting for new line

I'm trying to read from a file line by line that is tab delimited. Here's an example of a file:
state 0 start
state 5 accept
transition 0 0 1 x R
transition 1 0 0 x R
I create a Scanner object for the file and set the delimiter to \t. I loop through the file as long as there is a next line. I want to check whether a line begins with state or transition and then get the following information. In the case of lines that begin with state, I use nextInt() and then next() to obtain 0 and start respectively. The issue then arises of going to the next line and repeating the process. I use nextLine() and that's where things get ugly.
I'm aware that nextLine() does not consume the newline character, so I thought to use it twice and it creates more of an issue it seems.
Scanner sc = new Scanner(file);
sc.useDelimiter("\t");
while(sc.hasNextLine())
{
if(sc.next().equals("state") == true)
{
int stateNumber = sc.nextInt();
String state = sc.next();
sc.nextLine();
}
sc.nextLine();
}
That seems to be the relveant code that is creating issues.
Am I misunderstanding how next() works or am i missing something else entirely?
One option here would be to simply read in each entire line in one go, and then split by a delimeter (tab) to get the individual components:
which (sc.hasNextLine()) {
String line = sc.nextLine();
String[] parts = line.split("\\t");
if (parts[0].equals("state")) {
// construct custom object here
}
}
If you want to stick with your original approach then use this:
while(sc.hasNextLine()) {
if (sc.next().equals("state")) {
int stateNumber = sc.nextInt();
String state = sc.next();
}
// consume the entire remaining line, line break included
sc.nextLine();
}
For those lines containing "state" you were making two calls to nextLine(), which would result in an entire line being lost.

countTokens() always returns 1 with user input

Before we begin, I don't believe this is a repeat question. I've read the question entitled StringTokenzer countTokens() returns 1 with any string, but that does not address the fact that a properly delimited string is counted correctly, but a properly delimited input is not.
When using the StringTokenizer class I've found that the countTokens method returns different outcomes depending on the whether the argument in countTokens was a defined String or a user defined String. For example, the following code prints the value 4.
String phrase = "Alpha bRaVo Charlie delta";
StringTokenizer token = new StringTokenizer(phrase);
//There's no need to specify the delimiter in the parameters, but I've tried
//both code examples with " " as the delimiter with identical results
int count = token.countTokens();
System.out.println(count);
But this code will print the value 1 when the user enters:Alpha bRaVo Charlie delta
Scanner in = new Scanner(System.in);
String phrase;
System.out.print("Enter a phrase: ");
phrase = in.next();
StringTokenizer token = new StringTokenizer(phrase);
int count = token.countTokens();
System.out.println(count);
Use in.nextLine() instead of in.next();
Scanner in = new Scanner(System.in);
String phrase;
System.out.print("Enter a phrase: ");
phrase = in.nextLine();
System.out.print(phrase);
StringTokenizer token = new StringTokenizer(phrase);
int count = token.countTokens();
System.out.println(count);
Print phrase and check that in.next() is returning "Alpha".
As suggested above, Use in.nextLine().
You could try using an InputStreamReader, instead of the Scanner:
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String phrase = "";
System.out.print("Enter a phrase: ");
try {
phrase = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
StringTokenizer token = new StringTokenizer(phrase);
int count = token.countTokens();
System.out.println(count);
nextLine() of Scanner also got the job done for me, though.
If you want the delimiter to be a space-character specifically, you might want to pass it to the constructor of StringTokenizer. It will use " \t\n\r\f" otherwise (which includes the space-character, but might not work as expected if e.g. the \n-character is also present inside the phrase).
If you check the value of phrase, after invoking in.next(), you will see that's equal to "Alpha". By definition, Scanner's next() reads the next token.
Use in.nextLine() instead.

Java Scanner while loop

I'm trying to take in a string input which consists of multiple lines of numbers separated by ',' and ';' .
Example:
1,2;3,4;5,6;
9,8;7,6;
0,1;
;
Code:
ArrayList<Integer> alist = new ArrayList<>();
String delims = ";|\\,";
int i = 0;
Scanner input = new Scanner(System.in);
input.useDelimiter(delims);
while (input.hasNext()) {
alist.add(i, input.nextInt());
System.out.print(i + ' ');
System.out.print(alist.get(i) + '\n');
i++;
}
System.out.print('x');
When I run this in eclipse:
1,2;3,4;5,6; ( <= what i typed in console)
321133123413351436153716 ( <= output)
I'd expect something more like:
0 1
1 2
2 3
3 4
4 5
5 6
x
Why am I getting this sort of output?
One problem is that System.in is basically an infinite stream: hasNext will always return true unless the user enters a special command that closes it.
So you need to have the user enter something that tells you they are done. For example:
while(input.hasNext()) {
System.out.print("Enter an integer or 'end' to finish: ");
String next = input.next();
if("end".equalsIgnoreCase(next)) {
break;
}
int theInt = Integer.parseInt(next);
...
For your program, you might have the input you are trying to parse end with a special character like 1,2;3,4;5,6;end or 1,2;3,4;5,6;# that you check for.
And on these lines:
System.out.print(i + ' ');
System.out.print(alist.get(i) + '\n');
It looks like you are trying to perform String concatenation but since char is a numerical type, it performs addition instead. That is why you get the crazy output. So you need to use String instead of char:
System.out.print(i + " ");
System.out.print(alist.get(i) + "\n");
Or just:
System.out.println(i + " " + alist.get(i));
Edit for comment.
You could, for example, pull the input using nextLine from a Scanner with a default delimiter, then create a second Scanner to scan the line:
Scanner sysIn = new Scanner(System.in);
while(sysIn.hasNextLine()) {
String nextLine = sysIn.nextLine();
if(nextLine.isEmpty()) {
break;
}
Scanner lineIn = new Scanner(nextLine);
lineIn.useDelimiter(";|\\,");
while(lineIn.hasNextInt()) {
int nextInt = lineIn.nextInt();
...
}
}
Since Radiodef has already answered your actual problem(" instead of '), here are a few pointers I think could be helpful for you(This is more of a comment than an answer, but too long for an actual comment):
When you use Scanner, try to match the hasNextX function call to the nextX call. I.e. in your case, use hasNextInt and nextInt. This makes it much less likely that you will get an exception on unexpected input, while also making it easy to end input by just typing another delimiter.
Scanners useDelimiter call returns the Scanner, so it can be chained, as part of the initialisation of the Scanner. I.e. you can just write:
Scanner input = new Scanner(System.in).useDelimiter(";|\\,");
When you add to the end of an ArrayList, you don't need to(and usually should not) specify the index.
int i = 0, i++ is the textbook example of a for loop. Just because your test statement doesn't involve i does not mean you should not use a for loop.
Your code, with the above points addressed becomes as follows:
ArrayList<Integer> alist = new ArrayList<>();
Scanner input = new Scanner(System.in).useDelimiter(";|\\,");
for (int i = 0; input.hasNextInt(); i++) {
alist.add(input.nextInt());
System.out.println(i + " " + alist.get(i));
}
System.out.println('x');
Edit: Just had to mention one of my favorite delimiters for Scanner, since it is so suitable here:
Scanner input = new Scanner(System.in).useDelimiter("\\D");
This will make a Scanner over just numbers, splitting on anything that is not a number. Combined with hasNextInt it also ends input on the first blank line when reading from terminal input.

Keep doing stuff until empty line entered

I cant get this to work for some reason. I have an app that reads transactions, when an empty line in entered it needs to print out some stuff.
int transationCount = 0;
while(sc.hasNext())
{
String trans = sc.next();
String mode = trans.substring(0, 1);
Double amount = Double.valueOf(trans.substring(1));
if(mode.equals("C"))
{
c.charge(amount);
ps.println(c.getBalance());
transationCount = transationCount + 1;
}
else if(mode.equals("P"))
{
c.pay(amount);
ps.println(c.getBalance());
transationCount = transationCount + 1;
}
}
ps.println(c.getBalance());
ps.println(transationCount);
I tried
while(sc.hasNext() && !(sc.next().equals("")))
doesnt work. I also tried adding inside the while loop
else if (!(trans.equals("")) {break;}
By default, an empty line will be ignored by the scanner as it is not a valid token.
You could manually check if the line is empty:
public static void main(String[] args) throws Exception {
Scanner sc = new Scanner(System.in);
while(true) {
String line = sc.nextLine();
if (line.isEmpty()) {
System.out.println("Empty line entered");
} else {
System.out.println("received line: " + line);
String[] tokens = line.split("\\s+");
System.out.println("tokens: " + Arrays.toString(tokens));
}
}
}
Your Scanner is using the default delimiter (a whitespace) to tokenize the input.
This means that tokens are words, regardless of the lines they are in.
some
word
only returns two tokens, exactly as
some word
What you really need is to get lines separately, in order to tell which line is empty, and which line contain something. In order to do that, use new line as a separator:
Scanner.useDelimiter("\\n");
Or you might as well use BufferedReader, see BufferedReader.readLine()
Please note that two words on the same line will now be contained in the same trans string. You can use the String.split method to get each word separately.
So then how would I escape the while loop if an empty line is entered? Is there another way? – Infodayne
you can use label over/above your while loop, and break it when emptyLine is encountered
or alternatively you can use
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
while(! line.isEmpty()){
}
line.isEmpty() returns true when line is empty,So condition to enter while loop will become false as now inside while loop we have(! (true)) which equals to (false) therefore while loop will not execute.

Categories