net.avcompris.commons.query.impl.Tokenizer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of avc-commons3-query Show documentation
Show all versions of avc-commons3-query Show documentation
Common classes for avc-commons3 queries and filtering.
package net.avcompris.commons.query.impl;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.substringBefore;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import net.avcompris.commons.query.FilterSyntaxException;
final class Tokenizer {
// private final String expression;
private String current;
public Tokenizer(final String expression) {
// this.expression=
checkNotNull(expression, "expression");
current = expression;
}
@Override
public String toString() {
return "Tokenizer: " + current;
}
public String normalizeSpace() {
checkState(current != null, "current should not be null");
final String normalized = StringUtils.normalizeSpace(current);
if (!normalized.contentEquals(current)) {
setCurrent(normalized);
}
return current;
}
public String getCurrent() {
return current;
}
public Tokenizer setCurrent(@Nullable final String current) {
if (current == null) {
if (this.current != null) {
this.current = null;
}
} else if (this.current == null) {
checkState(false, //
"current != null (%s), while this.current == null", current);
} else if (current.length() > this.current.length()) {
checkState(false, //
"current.length (%s) = %s, while this.current.length (%s) = %s", //
current, current.length(), this.current, this.current.length());
} else {
this.current = current;
}
return this;
}
public boolean hasNext() {
return !isBlank(current);
}
public Tokenizer substringAfter(final String s) {
checkState(current != null, //
"current should not be null (s: %s)", s);
final String after = StringUtils.substringAfter(current, s);
checkState(after != null, //
"current (%s) doesn’t contain s: %s", current, s);
return setCurrent(after);
}
public Tokenizer substringAfter(final int length) {
checkState(current != null, //
"current should not be null (length: %s)", length);
checkState(current.length() >= length, //
"current.length = %s should not be >= length: %s", current.length(), length);
final String after = current.substring(length);
return setCurrent(after);
}
public ParsedArg nextArg() throws FilterSyntaxException {
return parseArgEscapeQuotes();
}
public static final class ParsedArg {
public final String s;
public final boolean hadQuotes;
private ParsedArg(final String s, final boolean hadQuotes) {
this.s = checkNotNull(s, "s");
this.hadQuotes = hadQuotes;
}
public boolean isNull() {
return "null".contentEquals(s) && !hadQuotes;
}
}
private ParsedArg parseArgEscapeQuotes() throws FilterSyntaxException {
final String s0 = getCurrent();
checkArgument(!isBlank(s0), //
"s: %s", s0);
String next = null;
final String trim = s0.trim();
final char firstChar = trim.charAt(0);
final boolean hadQuotes;
String s = s0;
if (firstChar == '(') {
throw new FilterSyntaxException("Illegal opening parenthesis.");
} else if (firstChar == ')') {
throw new FilterSyntaxException("Illegal closing parenthesis.");
} else if (firstChar == '"') {
hadQuotes = true;
s = parseQuotes(trim, '"');
next = trim.substring(s.length() + 2).trim();
s = s.replace("\\\"", "\"").replace("\\'", "'").replace("\\\\", "\\");
if (isBlank(next)) {
next = null;
}
} else if (firstChar == '\'') {
hadQuotes = true;
s = parseQuotes(trim, '\'');
next = trim.substring(s.length() + 2).trim();
s = s.replace("\\\"", "\"").replace("\\'", "'").replace("\\\\", "\\");
if (isBlank(next)) {
next = null;
}
} else if (s.contains(" ")) {
hadQuotes = false;
s = substringBefore(trim, " ");
next = trim.substring(s.length()).trim();
} else {
hadQuotes = false;
}
// return parseArgDontEscapeQuotes(s, hadQuotes, next);
setCurrent(next);
return new ParsedArg(s, hadQuotes);
}
private static String parseQuotes(final String s, final char quoteChar) {
final StringBuilder sb = new StringBuilder();
boolean escape = false;
boolean inQuotes = false;
for (char c : s.toCharArray()) {
if (c == '\\') {
escape = !escape;
} else if (c == quoteChar) {
if (!escape) {
if (inQuotes) {
return sb.toString();
} else {
inQuotes = true;
continue;
}
} else {
escape = false;
}
} else {
escape = false;
}
sb.append(c);
}
throw new IllegalArgumentException("Unclosed quotes in: " + s);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy