Java Scanner - Ignore Subsequent Letters - java

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

Related

I want to read those inputs in a single line separated by space in java without using String?

System.out.println("Number of pages + Number of lost pages + Number of Readers");
int n = s.nextInt();
int m = s.nextInt();
int q = s.nextInt();
I want to read input values all the values are going to be integer but I want to read it in a same line with changing it form Integer.
Assuming s is an instance of Scanner: Your code, as written, does exactly what you want.
scanners are created by default with a delimiter configured to be 'any whitespace'. nextInt() reads the next token (which are the things in between the delimiter, i.e. the whitespace), and returns it to you by parsing it into an integer.
Thus, your code as pasted works fine.
If it doesn't, stop setting up a delimiter, or reset it back to 'any whitespace' with e.g. scanner.reset(); or scanner.useDelimiter("\\s+");.
class Example {
public static void main(String[] args) {
var in = new Scanner(System.in);
System.out.println("Enter something:");
System.out.println(in.nextInt());
System.out.println(in.nextInt());
System.out.println(in.nextInt());
}
}
works fine here.

Java - Counting words, lines, and characters from a file

I'm trying to read in words from a file. I need to count the words, lines, and characters in the text file. The word count should only include words (containing only alphabetic letters, no punctuation, spaces, or non-alphabetic characters). The character count should only include the characters inside those words.
This is what I have so far. I'm unsure of how to count the characters. Every time I run the program, it jumps to the catch mechanism as soon as I enter the file name (and it should have no issues with the file path, as I've tried using it before). I tried to create the program without the try/catch to see what the error was, but it wouldn't work without it.
Why is it jumping to the catch function when I enter the file name? How can I fix this program to properly count words, lines, and characters in the text file?
I don't get any exception with your code if I give a proper file name. As for reading the number of character, you should modify the logic a little bit. Instead of directly concatenating the number of words count, you should create a new instance of StringTokenizer st = new StringTokenizer(tempo, "[ .,:;()?!]+"); and iterate through all the token and sum the length of each token. This should give you the number of characters. Something like below
while (fileScan.hasNextLine()) {
lineC++;
tempo = fileScan.nextLine();
StringTokenizer st = new StringTokenizer(tempo, "[ .,:;()?!]+");
wordC += st.countTokens();
while(st.hasMoreTokens()) {
String stt = st.nextToken();
System.out.println(stt); // Displaying string to confirm that like is splitted as I expect it to be
charC += stt.length();
}
System.out.println("Lines: " + lineC + "\nWords: " + wordC+" \nChars: "+charC);
}
Note: Escaping character with StringTokenizer will not work. i.e. you would expect that \\s should delimit with any whitespace character but it will instead delimit based on literal character s. If you want to escape a character, I suggest you to use java.util.Pattern and java.util.Matcher and use it matcher.find() to idenfity words and characters
I tried your code but I didn't receive any exception here. However, I suspect that when you input the file name, maybe you forgot the extension of the file.
You probably forgot the file extension while giving input, but there is a much simpler way of doing this. You also mention you don't know how to count the characters. You can try something like this:
import java.util.Scanner;
import java.util.StringTokenizer;
import java.io.*;
import java.util.stream.*;
public class WordCount
{
public static void main(String[] args)
{
Scanner userInput = new Scanner(System.in);
try {
// Input file
System.out.println("Please enter the name of the file.");
String content = Files.readString(Path.of("C:/Users/garre/OneDrive/Desktop/" + userInput.next()));
System.out.printf("Lines: %d\nWords: %d\nCharacters: %d",content.split("\n").length,Stream.of(content.split("[^A-Za-z]")).filter(x -> !x.isEmpty()).count(),content.length());
}
catch (IOException ex1) {
System.out.println("Error.");
System.exit(0);
}
}
}
Going through the code
import java.util.stream.*;
Note we use the streams package, for filtering out empty strings while finding words. Now let's skip forward a bit.
String content = Files.readString(Path.of("C:/Users/garre/OneDrive/Desktop/" + userInput.next()));
The above part gets all of the text in the file and stores it as a string.
System.out.printf("Lines: %d\nWords: %d\nCharacters: %d",content.split("\n").length,Stream.of(content.split("[^A-Za-z]")).filter(x -> !x.isEmpty()).count(),content.length());
Okay, this is a long line. Let's break it down.
"Lines: %d\nWords: %d\nCharacters: %d" is a format string, where each %d is replaced with the corresponding argument in the printf function. The first %d will be replaced by content.split("\n").length, which is the number of lines. We get the number of lines by splitting the string.
The second %d is replaced by Stream.of(content.split("[^A-Za-z]")).filter(x -> !x.isEmpty()).count(). Stream.of creates a stream from an array, and the array is an array of strings after you split on anything that is non-alphabetic (you said words are anything that are non-alphabetic). Next, we filter all the empty values out, since String.split keeps in empty values. The .count() is self-explanatory, takes the amount of words left after filtering.
The third and last %d is the simplest. It is replaced by the length of the string. content.length() should be self-explanatory.
I left your catch block intact, but I feel like the System.exit(0) is a bit redundant.

Java: Parse lines from files

I am in need of some ideas. I have a file with some information like this:
AAA222BBB%
CC333DDDD%
EEEE444FF%
The '%' sign is like an indicator of "end of line"
I would like to read every line, and then parse it to fit a certain format (4 letters, 3 digits and 4 letters again) - So if it looks like the above, it should insert a special sign or whitespace to fill, like this:
AAA-222BBB-%
CC--333DDDD%
EEEE444FF--%
My first and immediate idea was to read every line as a string. And then some huge if-statement saying something like
For each line:
{
if (first symbol !abc...xyz) {
insert -
}
if (second symbol !abc...xyz) {
insert -
}
}
However, I am sure there must be a more elegant and effective way, do to a real parsing of the text, but I'm not sure how. So if anyone has a good idea please enlighten me :-)
Best
My first advice is to read this other post (nice explanation of scanner and regex):
How do I use a delimiter in Java Scanner?
Then my solution (sure it is the the cleverest, but it should work)
For each line:
{
Scanner scan = new Scanner(line);
scan.useDelimiter(Pattern.compile("[0-9]"));
String first = scan.next();
scan.useDelimiter(Pattern.compile("[A-Z]"));
String second = scan.next();
scan.useDelimiter(Pattern.compile("[0-9]"));
String third = scan.next();
scan.close();
System.out.println(addMissingNumber(first, 4) + addMissingNumber(second, 3) + addMissingNumber(third, 4));
}
//For each missing char add "-"
private static String addMissingNumber(String word, int size) {
while (word.length() < size) {
word = word.concat("-");
}
return word;
}
The output: "AAA-222BBB-"

How to make a program accept a line of different input-types from terminal in java?

I have a quick question about an assignment which I have. I want to make a sort of a calculator which will read the input from user, use an if-else-loop to figure out what to do with it and then print the corresponding result.
So if the user inputs: 4 * 5, I want the program to check for two ints, and with a inChar check the type of calculation needed, then an if-else-loop which will do the rest (I know how to write this part) but I need some help on how to write the scanner-sentences where it checks for the different types of input from one line. Hope you understood what I meant.
The part of code which I already have:
Scanner input = new Scanner(System.in);
int a,b;
char c;
double sum;
System.out.println("Velkommen til en helt enkel kalkulator!");
System.out.println("Vennligst tast inn regnestykket, paa formen: tall, regneart, tall med mellomrom imellom hver input: ");
String svar=input.nextLine();
if(c='*'){
sum=a*b;
}else if(c='/'){
sum=a/b;
}else if(c='+'){
sum=a+b;
}else if(c='-'){
sum=a-b;
}else{
System.out.println("Regnearten var ikke forstaaelig. Programmet termineres.");
}
Read your input line by line and parse it after that using either String.split() or Pattern. To read lines use either Scanner or System.in wrapped with BufferedReader
I love regular expressions! So lets use one: (\d+)\s*([*/+-])\s*(\d+)
Broken down:
\d+ = One or more digits
\s* = "Space" zero or more times
[*/+-] = One of *, /, +, or -
The parentheses "capture" the matched elements, so you can access them later. In java, use Matcher.group(int), like shown in the fragment below:
//Do this only once in your program
Pattern calcPattern = Pattern.compile("(\\d+)\\s*([*/+-])\\s*(\\d+)");
//Do this in your loop
Matcher m = calcPattern.matcher(input.nextLine());
if (m.matches()) {
a = Integer.parseInt(m.group(1)); //Get the first group (first set of digits)
c = m.group(2); //Get the second group (operator)
b = Integer.parseInt(m.group(3)); //Get the third group (second set of digits)
//do stuff with a, b, and c
} else {
System.out.println("Please enter a valid expression!");
}
As you progress in skill, the regular expression is easily extendable - replace (\d+) with (\d+(?:.?\d+)?) to accept numbers with decimals, for instance. Play around with an online regexp tester here: http://rubular.com/r/8VibLUpxqP
(Quick note: the double backslashes in the regular expression in the java code are necessary because you can't write a single backslash in a string - http://docs.oracle.com/javase/tutorial/java/data/characters.html)

How to test for blank line with Java Scanner?

I am expecting input with the scanner until there is nothing (i.e. when user enters a blank line). How do I achieve this?
I tried:
while (scanner.hasNext()) {
// process input
}
But that will get me stuck in the loop
Here's a way:
Scanner keyboard = new Scanner(System.in);
String line = null;
while(!(line = keyboard.nextLine()).isEmpty()) {
String[] values = line.split("\\s+");
System.out.print("entered: " + Arrays.toString(values) + "\n");
}
System.out.print("Bye!");
From http://www.java-made-easy.com/java-scanner-help.html:
Q: What happens if I scan a blank line with Java's Scanner?
A: It depends. If you're using nextLine(), a blank line will be read
in as an empty String. This means that if you were to store the blank
line in a String variable, the variable would hold "". It will NOT
store " " or however many spaces were placed. If you're using next(),
then it will not read blank lines at all. They are completely skipped.
My guess is that nextLine() will still trigger on a blank line, since technically the Scanner will have the empty String "". So, you could check if s.nextLine().equals("")
The problem with the suggestions to use scanner.nextLine() is that it actually returns the next line as a String. That means that any text that is there gets consumed. If you are interested in scanning the contents of that line… well, too bad! You would have to parse the contents of the returned String yourself.
A better way would be to use
while (scanner.findInLine("(?=\\S)") != null) {
// Process the line here…
…
// After processing this line, advance to the next line (unless at EOF)
if (scanner.hasNextLine()) {
scanner.nextLine();
} else {
break;
}
}
Since (?=\S) is a zero-width lookahead assertion, it will never consume any input. If it finds any non-whitespace text in the current line, it will execute the loop body.
You could omit the else break; if you are certain that the loop body will have consumed all non-whitespace text in that line already.
Scanner key = new Scanner(new File("data.txt"));
String data = "";
while(key.hasNextLine()){
String nextLine = key.nextLine();
data += nextLine.equals("") ? "\n" :nextLine;
}
System.out.println(data);
AlexFZ is right, scanner.hasNext() will always be true and loop doesn't end, because there is always string input even though it is empty "".
I had a same problem and i solved it like this:
do{
// process input
}while(line.length()!=0);
I think do-while will fit here better becasue you have to evaluate input after user has entered it.

Categories