com.univocity.parsers.common.input.LookaheadCharInputReader Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of univocity-parsers Show documentation
Show all versions of univocity-parsers Show documentation
univocity's open source parsers for processing different text formats using a consistent API
/*******************************************************************************
* Copyright 2015 uniVocity Software Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package com.univocity.parsers.common.input;
import java.io.*;
import java.util.*;
/**
* A special implementation of {@link CharInputReader} that wraps another {@link CharInputReader} and
* collects a sequence of characters from the wrapped input, in order to analyze what the buffer contains
* ahead of the current position.
*/
public class LookaheadCharInputReader implements CharInputReader {
private final CharInputReader reader;
private char[] lookahead = new char[0];
private int length = 0;
private int start = 0;
private final char newLine;
private char delimiter;
/**
* Creates a lookahead input reader by wrapping a given {@link CharInputReader} implementation
*
* @param reader the input reader whose characters will read and stored in a limited internal buffer,
* in order to allow a parser to query what the characters are available ahead of the current input position.
*/
public LookaheadCharInputReader(CharInputReader reader, char newLine) {
this.reader = reader;
this.newLine = newLine;
}
/**
* Matches a sequence of characters against the current lookahead buffer.
*
* @param current the last character used by the parser, which should match the first character in the lookahead buffer
* @param sequence the expected sequence of characters after the current character, that are expected appear in the current lookahead buffer
*
* @return {@code true} if the current character and the sequence characters that follows are present in the lookahead, otherwise {@code false}
*/
public boolean matches(char current, char[] sequence) {
if (sequence.length > length - start) {
return false;
}
if (sequence[0] != current) {
return false;
}
for (int i = 1; i < sequence.length; i++) {
if (sequence[i] != lookahead[i - 1 + start]) {
return false;
}
}
return true;
}
/**
* Matches a sequence of characters against the current lookahead buffer.
*
* @param sequence the expected sequence of characters that are expected appear in the current lookahead buffer
*
* @return {@code true} if the given sequence of characters is present in the lookahead, otherwise {@code false}
*/
public boolean matches(char[] sequence) {
if (sequence.length > length - start) {
return false;
}
for (int i = 0; i < sequence.length; i++) {
if (sequence[i] != lookahead[i + start]) {
return false;
}
}
return true;
}
/**
* Returns the current lookahead value.
*
* @return the current lookahead value, or an empty {@code String} if the lookahead buffer is empty.
*/
public String getLookahead() {
if (start >= length) {
return "";
}
return new String(lookahead, start, length);
}
/**
* Returns the lookahead value prepended with the current character
*
* @param current the current character obtained by the parser
*
* @return a {@code String} formed by the given character followed by the lookahead value (if any).
*/
public String getLookahead(char current) {
if (start >= length) {
return String.valueOf(current);
}
return current + new String(lookahead, start, length - 1);
}
/**
* Fills the lookahead buffer with a given number of characters that will be extracted from the wrapped {@link CharInputReader}
*
* @param numberOfCharacters the number of characters to read from the wrapped {@link CharInputReader}, given in the constructor of this class.
*/
public void lookahead(int numberOfCharacters) {
numberOfCharacters += length - start;
if (lookahead.length < numberOfCharacters) {
lookahead = Arrays.copyOf(lookahead, numberOfCharacters);
}
if (start >= length) {
start = 0;
length = 0;
}
try {
numberOfCharacters -= length;
while (numberOfCharacters-- > 0) {
lookahead[length] = reader.nextChar();
length++;
}
} catch (EOFException ex) {
//ignore.
}
}
@Override
public void start(Reader reader) {
this.reader.start(reader);
}
@Override
public void stop() {
this.reader.stop();
}
@Override
public char nextChar() {
if (start >= length) {
return reader.nextChar();
} else {
return lookahead[start++];
}
}
@Override
public long charCount() {
return reader.charCount();
}
@Override
public long lineCount() {
return reader.lineCount();
}
@Override
public void skipLines(long lineCount) {
reader.skipLines(lineCount);
}
@Override
public void enableNormalizeLineEndings(boolean escaping) {
reader.enableNormalizeLineEndings(escaping);
}
@Override
public String readComment() {
return reader.readComment();
}
@Override
public char[] getLineSeparator() {
return reader.getLineSeparator();
}
@Override
public final char getChar() {
if (start != 0 && start >= length) {
return reader.getChar();
} else {
return lookahead[start - 1];
}
}
@Override
public char skipWhitespace(char ch, char stopChar1, char stopChar2) {
while (start < length && ch <= ' ' && ch != stopChar1 && ch != newLine && ch != stopChar2) {
ch = lookahead[start++];
}
return reader.skipWhitespace(ch, stopChar1, stopChar2);
}
}