import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.function.Predicate;
public class CastScanner implements AutoCloseable {
private final Reader reader;
private final char[] buffer;
private int pose = -2;
private int bufferLength;
private final char lineSep = System.lineSeparator().charAt(System.lineSeparator().length() - 1);
private final Predicate filter;
public CastScanner(InputStream in, Predicate filter) {
this (new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)), filter);
}
public CastScanner(File in, Predicate filter) throws FileNotFoundException {
this(new BufferedReader(new InputStreamReader(new FileInputStream(in), StandardCharsets.UTF_8)), filter);
}
public CastScanner(Reader in, Predicate filter) {
this.reader = in;
this.filter = filter;
this.buffer = new char[8192];
}
private boolean hasNextChar() throws IOException {
if (newBuffer() && bufferLength != -1) {
if ((pose != bufferLength && (isCorrectChar(buffer[pose]) || buffer[pose] == lineSep || buffer[pose] == '\r')) ||
!filter.test(buffer[pose])) {
nextChar();
return false;
}
return true;
}
return false;
}
private void nextChar() throws IOException {
while (newBuffer()) {
while ((bufferLength != -1) && (pose != bufferLength) &&
((isCorrectChar(buffer[pose]) || buffer[pose] == lineSep || buffer[pose] == '\r') ||
!filter.test(buffer[pose]))) {
if (buffer[pose] == lineSep || buffer[pose] == '\r') {
break;
}
pose++;
}
if (pose != bufferLength) {
break;
}
}
}
private boolean newBuffer() throws IOException {
if (pose == -2 || pose == bufferLength) {
bufferLength = reader.read(buffer);
pose = 0;
} else return bufferLength != -1;
return true;
}
public boolean hasNext() throws IOException {
newBuffer();
return bufferLength != -1;
}
public boolean hasNextInLine() throws IOException {
if (!(newBuffer() && buffer[pose] != lineSep && buffer[pose] != '\r')) {
pose += 1;
return false;
}
return true;
}
public String next() throws IOException {
StringBuilder word = new StringBuilder();
while (true) {
if (hasNextChar()) {
word.append(buffer[pose]);
pose++;
} else {
break;
}
}
return word.toString();
}
private static boolean isDash(char ch) {
return Character.getType(ch) == Character.DASH_PUNCTUATION;
}
private static boolean isCorrectChar(char ch) {
return (!Character.isLetter(ch) && ch != '\'' && !isDash(ch) && !Character.isDigit(ch) &&
ch != '$' && ch != '_' && !Character.isDigit(ch));
}
public void close() throws IOException {
reader.close();
}
}