Split command does not function with Scanner - java

I tried doing something like what these people have done:
How to split a comma-separated string?
But when I do the following:
String UserInput = new Scanner(System.in).next();
GradesNonInt = Arrays.asList(UserInput.replaceAll("\\s","").split(","));
System.out.println(GradesNonInt.size());
When I input a string like "1,2,3" I get 3 printed. When I type "1, 2, 3" I get 1 printed. For some reason, it does not want to work when the string has spaces in it.
As one of the answers below said, entering "1, 2, 3" directly seems to work fine, but yet when taken from the Scanner(System.in).next(), it is not.

I tried following code and it printed 3 when I used "1, 2, 3" in UserInput string
String UserInput = "1, 2, 3";
List<String> GradesNonInt = Arrays.asList(UserInput.replaceAll("\\s","").split(","));
System.out.println(GradesNonInt.size());
The issue is not with split but this is happening cause Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace and that's why this behaviour is shown. Refer this link.
If you want you can change the delimiter to something else than space by using useDelimiter method of Scanner class
UPDATE
To change the delimiter to next line and to ensure the code accept spaces in the strings, you can change your code to following
String UserInput = new Scanner(System.in).useDelimiter("\n").next();
List<String> GradesNonInt = Arrays.asList(UserInput.replaceAll("\\s","").split(","));
System.out.println(GradesNonInt.size());

Problem is that Scanner#next() can return only next token (until it finds next delimiter, or end of data). So for input like 1, 2, 3, it will return 1,.
Use Scanner#nextLine() to read entire line.
Also don't create new instance of Scanner each time you want to read data from user. Create one Scanner handling System.in per application and reuse it.

Related

java: Scanner asks for an extra value when using useDelimiter

So I wanna create this program that stores 4 values. the first one being string and the remaining 3 being integers. However, when i enter 4 values and press enter, i get an error java.util.InputMismatchException but when I enter 5 values, i get the result for my for values. for example lets say i input the following values:
Japan,1,2,3
I will get the java.util.InputMismatchException error. And if I enter the following values:-
Japan,1,2,3,4
I get the output as I want:-
Japan,1,2,3
Why is this happening? Here is my code
public class satisfaction {
public static void main(String args[])
{
Scanner src= new Scanner(System.in);
src.useDelimiter("\\,|\\n");
String name=src.next();
int a=src.nextInt();
int b=src.nextInt();
int c=src.nextInt();
System.out.println(name+","+a+","+b+","+c);
}
}
I've tested this a bit myself, and I think the \n in the pattern is not matching the line ending used by your console.
For me, I had to use \r\n instead, but you could also use System.lineSeparator() e.g. like this:
src.useDelimiter(",|" + System.lineSeparator());
The way it's written, it needs another comma at the end of the input. I would recommend checking the string to make sure it ends in a comma, and if not, append one.
I believe that if you enter Japan,1,2,3, it will give you the output you want.

Read integers and string from a list using a scanner

I am reading a string from stdin that's formatted as a list. I am using the information from the string to create objects.
An example input string would be formatted as follows:
1 apple, 3 bananas, 2 pears
I want to read that line a create objects as I go, but my biggest issue is properly reading the line to get the number of items, followed by them item itself while also skipping whitespace and commas.
I have tried the following:
Scanner input = new Scanner(System.in);
input.useDelimeter(",|\\s");
while(input.hasNext()){
int numItems = input.nextInt();
String item = input.next();
// create object and add to object array
}
Which works for the first iteration (1 apple) but fails on the second with a type mismatch. Can anyone suggest a fix or alternate solution?
Thanks!
,|\\s declares two separate delimiters. Those delimiters can be matched in text "apple, 3" twice:
comma after apple
space before 3
apple, 3
^^
12
so we split that text at two separate (middle) places, which means we split it into 3 tokens:
"apple",
"",
"3".
When in next iteration (after calling input.next() which consumes apple) you are calling input.nextInt() Scanner tries to parse second token as int, but since it finds empty string it is throwing exception.
One of solutions would be treating [space] or ,[space] as single delimiter. You can achieve it by making comma optional:
input.useDelimiter(",?\\s");
Demo:
Scanner input = new Scanner("1 apple, 3 bananas, 2 pears");
input.useDelimiter(",?\\s");
while(input.hasNext()){
int numItems = input.nextInt();
System.out.println(numItems);
String item = input.next();
System.out.println(item);
System.out.println("----");
}
Output:
1
apple
----
3
bananas
----
2
pears
----
You can spilt the input String using delimiter "," and get following output after using trim() method.
1 apple
3 bananas
2 pears
Here is the code:
String [] array1 = input.nextLine().split(",");
for(int i=0; i<array1.length; i++){
System.out.println(array1[i].trim());
}
Edit: You can further split the Strings inside for loop using delimiter space, to get the desired output.

Java Scanner - Ignore Subsequent Letters

My program needs to accept integer numbers, individual characters, or one specific string (I'll use "pear" for this example). Whilst each of these can be separated by whitespace, there shouldn't be any need to.
Currently, my parsing code, which relies on a Scanner, looks something like this:
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
if (scanner.hasNext("\\s+")) {
// Ignore whitespace…
} else if (scanner.hasNext("[-]?\\d+")) {
// Get a number
String nextNumberString = scanner.next("[-]?\\d+");
// Process the string representing the number…
} else if (scanner.hasNext("pear")) {
scanner.next("pear");
// Do something special…
} else {
// Get the next character
Pattern oldDelimiter = scanner.delimiter();
scanner.useDelimiter("");
String nextCharAsString = scanner.next();
scanner.useDelimiter(oldDelimiter);
char nextCharacter = nextCharAsString.charAt(0);
if (Character.isWhitespace(nextCharacter)) {
// Ignore whitespace…
} else {
// Process character…
}
}
}
At present, my program will accept input like 123 d 456 r pear without any problems. However, it should also accept the same input without any whitespace (123d456rpear), and interpret it the same way, and with my current code, the individual digits are incorrectly interpreted as characters.
I feel like the cause might be the regular expressions that I'm using. However, adding .* to the end of them will cause all of the subsequent characters to be parsed, along with the input that I'm trying to parse. For example, [-]?\d+.* will try to parse the entirety of 123d456rpear as a number, when I really just want 123, leaving the rest to be parsed later. I've also tried wrapping my desired input into a group, and then appending ? or {1}, which hasn't worked, either.
I've also experimented with scanner.findInLine(), but in my testing, this doesn't seem to work either. For example, when I tried this, pearpear would cause an infinite loop, despite my attempts to skip the first instance of pear.
I've also tried setting the delimiter to "", like I do when extracting individual characters (which, in that case, works as expected). However, this causes each individual number to be processed individually, parsing 1, 2, and 3 instead of 123. pear also gets interpreted as individual characters.
So, could someone help me figure out where I'm going wrong? Does this issue lie with my regular expressions? Am I using the wrong methods? Or am I misunderstanding how the Scanner class is designed to work?
To my understanding the idea of the Scanner class is to extract tokens and to throw the delimiters away. But you don't want to throw anything away but whitespaces. However whitespaces are not required in your input. Here is an implementation idea by using an outer and an inner Scanner. The outer tokenizes at whitespaces - if any. The inner uses findInLine() to bypass delimiters at all.
findInLine
Attempts to find the next occurrence of a pattern constructed from the
specified string, ignoring delimiters.
public void scan(Scanner scanner) {
while (scanner.hasNext()) {
String next = scanner.next();
System.out.println("opening inner scanner: " + next);
Scanner innerScanner = new Scanner(next);
do {
next = innerScanner.findInLine("([-]?\\d+)|(pear)|([a-zA-Z])");
if (next == null) {
// Nothing useful in there
} else if (next.equals("pear")) {
System.out.println("pear");
} else if (next.matches("[a-zA-Z]")) {
System.out.println("char: " + next);
} else {
System.out.println("number: " + next);
}
} while (next != null);
innerScanner.close();
}
}
public void run() {
scan(new Scanner("123 d 456 pear"));
scan(new Scanner("123d456pear"));
}
The output of the run() method is as follows:
opening inner scanner: 123
number: 123
opening inner scanner: d
char: d
opening inner scanner: 456
number: 456
opening inner scanner: pear
pear
opening inner scanner: 123d456pear
number: 123
char: d
number: 456
pear
Well the individual digits are incorrectly interpreted as characters because hasNext method of Scanner extracts the token from the given by the delimiter which defaults to whitespace
From java docs
A Scanner breaks its input into tokens using a delimiter pattern,
which by default matches whitespace. The resulting tokens may then be
converted into values of different types using the various next
methods
Hence the whole 123d456rpear is extracted which is not a number but a string

How do I change the delimiter from a text file?

Let's say I got a textfile.txt that I want to read from. This is the text in the file:
23:years:old
15:years:young
Using the useDelimiter method, how can I tell my program that : and newlines are delimiters? Putting the text in one line and using useDelimter(":"); works. The problem is when I got several lines of text.
Scanner input = new Scanner(new File("textfile.txt));
input.useDelimiter(:);
while(data.hasNextLine()) {
int age = input.nextInt();
String something = input.next();
String somethingelse = input.next();
}
Using this code I will get an inputMisMatch error.
Try
scanner.useDelimiter("[:]+");
The complete code is
Scanner scanner = new Scanner(new File("C:/temp/text.txt"));
scanner.useDelimiter("[:]+");
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
The output is
23
years
old
15
years
young
Use this code
Scanner input;
String tokenizer[];
try {
input = new Scanner(new File("D:\\textfile.txt"));
input.useDelimiter("\\n");
while(input.hasNextLine()) {
tokenizer = input.next().split(":");
System.out.println(tokenizer[0]+" |"+tokenizer[1]+" | "+tokenizer[2]);
}
}catch(Exception e){}
It will give you output like
23 |years | old
15 |years | young
You have two ways to do this:
Concatenate the string to make it one line.
delimit "newline" first, then delimit ":" each return string token.
If all you want is to get everything split up all at once then I guess you can use
useDelimiter(":\\n")
That should split on both : and newspace but it is not the most efficient way of processing data, especially if each line of text is set out in the same format and represents a complete entry. If that is the case then my suggestion would be to only split on a new line to begin with, like this;
s.useDelimiter("\\n");
while(s.hasNext()){
String[] result = s.next.split(":");
//do whatever you need to with the data and store it somewhere
}
This will allow you to process the data line by line and will also split it at the required places. However if you do plan on going through line by line I recommend you look at BufferedReader as it has a readLine() function that makes things a lot easier.
As long as all the lines have all three fields you can just use input.useDelimiter(":\n");
you probably wants to create a delimiter pattern which includes both ':' and newline
I didn't test it, but [\s|:]+ is a regular expression that matches one or more whitespace characters, and also ':'.
Try put:
input.useDelimiter("[\\s|:]+");

Scanner, useDelimiter

I encounter some problem when using useDelimiter from the Scanner class.
Scanner sc = new Scanner(System.in).useDelimiter("-");
while(sc.hasNext())
{
System.out.println(sc.next());
}
if I have this input
A-B-C
the output will be
A B
and wait until I type in another "-" for it to print out the last character
However if I instead of having user input data, and insert a String to the Scanner instead the code will work. What's the reason for it, and how do I fix it? I don't want to use StringTokenzier
If the Scanner didn't wait for you to enter another - then it would erroneously assume that you were done typing input.
What I mean is, the Scanner must wait for you to enter a - because it has no way to know the length of the next input.
So, if a user wanted to type A-B-CDE and you stopped to take a sip of coffee at C, it woud not get the correct input. (You expect [ A, B, CDE ] but it would get [ A, B, C ])
When you pass it in a full String, Scanner knows where the end of the input is, and doesn't need to wait for another delimiter.
How I would do it follows:
Scanner stdin = new Scanner(System.in);
String input = stdin.nextLine();
String[] splitInput = input.split("-", -1);
You will now have an array of Strings that contain the data between all of the -s.
Here is a link to the String.split() documentation for your reading pleasure.
You could use an alternative delimiter string useDelimiter( "-|\n" );
It works with a String argument as well as by reading from System.in.
In case of System.in this requires you to press enter at the end of the line.
How I would do it follows:
Scanner stdin = new Scanner(System.in);
String s = stdin.nextLine();
String[] splitInput = s.split("-", -1);
You will now have an array of Strings that contain the data between all of the -s.

Categories