All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.lenni0451.commandlib.utils.StringReader Maven / Gradle / Ivy

package net.lenni0451.commandlib.utils;

import java.util.Arrays;
import java.util.regex.Pattern;

/**
 * A simple string reader used for parsing arguments.
 */
public class StringReader {

    private static final Pattern STRING_ESCAPE_REPLACEMENT = Pattern.compile("\\\\(.)");


    private final String string;
    private int cursor = 0;

    public StringReader(final String string) {
        this.string = string;
    }

    /**
     * @return The string that is read
     */
    public String getString() {
        return this.string;
    }

    /**
     * @return The current cursor position
     */
    public int getCursor() {
        return this.cursor;
    }

    /**
     * Set the cursor position.
     *
     * @param cursor The new cursor position
     * @return The string reader
     */
    public StringReader setCursor(final int cursor) {
        this.cursor = cursor;
        return this;
    }

    /**
     * @return The length of the string
     */
    public int length() {
        return this.string.length();
    }

    /**
     * @return The amount of remaining characters
     */
    public int remaining() {
        return this.string.length() - this.cursor;
    }

    /**
     * @return If the reader can read at least one character
     */
    public boolean canRead() {
        return this.canRead(1);
    }

    /**
     * Get if the reader can read the given amount of characters.
     *
     * @param length The amount of characters
     * @return If the reader can read the given amount of characters
     */
    public boolean canRead(final int length) {
        return this.cursor + length <= this.string.length();
    }

    /**
     * Ensure that the reader can read the given amount of characters.
     *
     * @param length The amount of characters
     * @return The string reader
     * @throws StringIndexOutOfBoundsException If the reader cannot read the given amount of characters
     */
    public StringReader ensureLength(final int length) {
        if (!this.canRead(length)) throw new StringIndexOutOfBoundsException("Cannot read " + length + " chars");
        return this;
    }

    /**
     * Require the next character to be in the given array.
     *
     * @param cs The array of characters
     * @return The string reader
     * @throws IllegalStateException If the nothing can be read or the next character is not in the given array
     */
    public StringReader require(final char... cs) {
        if (!this.canRead()) throw new IllegalStateException("Expected " + Arrays.toString(cs) + " but got ");
        if (cs.length == 0) return this;
        for (char c : cs) {
            if (this.peek() == c) return this;
        }
        throw new IllegalStateException("Expected " + Arrays.toString(cs) + " but got '" + this.peek() + "'");
    }

    /**
     * @return The next character without moving the cursor
     */
    public char peek() {
        return this.peek(0);
    }

    /**
     * Get the character with the given offset without moving the cursor.
     *
     * @param offset The offset
     * @return The character with the given offset
     */
    public char peek(final int offset) {
        this.ensureLength(1 + offset);
        return this.string.charAt(this.cursor + offset);
    }

    /**
     * @return The remaining string without moving the cursor
     */
    public String peekRemaining() {
        return this.string.substring(this.cursor);
    }

    /**
     * Skip all whitespace characters.
* If nothing can be read, nothing will happen. * * @return The string reader */ public StringReader skipWhitespace() { while (this.canRead() && Character.isWhitespace(this.peek())) this.cursor++; return this; } /** * Skip all whitespace characters and ensure that at least one character was skipped.
* If nothing can be read, an exception will be thrown. * * @return The string reader * @throws IllegalStateException If nothing can be read or the next character is not a whitespace character */ public StringReader skipRequiredWhitespace() { if (!this.canRead()) throw new IllegalStateException("Expected whitespace but got "); if (!Character.isWhitespace(this.peek())) throw new IllegalStateException("Expected whitespace but got '" + this.peek() + "'"); this.skipWhitespace(); return this; } /** * Skip all whitespace characters and ensure that at least one character was skipped.
* If nothing can be read, nothing will happen. * * @return The string reader * @throws IllegalStateException If the next character is not a whitespace character */ public StringReader skipRequiredWhitespaceOrEOL() { if (!this.canRead()) return this; if (!Character.isWhitespace(this.peek())) throw new IllegalStateException("Expected whitespace or EOL but got '" + this.peek() + "'"); this.skipWhitespace(); return this; } /** * Move the cursor by one character. * * @return The string reader */ public StringReader skip() { return this.skip(1); } /** * Move the cursor by the given amount of characters. * * @param length The amount of characters * @return The string reader * @throws StringIndexOutOfBoundsException If the given amount of characters is not available */ public StringReader skip(final int length) { this.ensureLength(length); this.cursor += length; return this; } /** * @return The next character and move the cursor by one character */ public char read() { return this.string.charAt(this.cursor++); } /** * Read the given amount of characters and move the cursor by the given amount of characters. * * @param length The amount of characters * @return The read characters * @throws StringIndexOutOfBoundsException If the given amount of characters is not available */ public String read(final int length) { this.ensureLength(length); int start = this.cursor; this.cursor += length; return this.string.substring(start, this.cursor); } /** * Read until the given character is found or the end of the string is reached.
* The character will not be read. * * @param c The character * @return The read characters */ public String readUntil(final char c) { return this.readUntil(c, false); } /** * Read until the given character is found or the end of the string is reached.
* The character will not be read.
* If the given character is escaped using a backslash, it will be ignored. The backslash will be removed. * * @param c The character * @param allowEscape Whether to allow escaping * @return The read characters */ public String readUntil(final char c, final boolean allowEscape) { int start = this.cursor; while (this.canRead()) { if (this.peek() == c) break; if (allowEscape && this.peek() == '\\') this.cursor++; this.cursor++; } String s = this.string.substring(start, this.cursor); if (allowEscape) s = STRING_ESCAPE_REPLACEMENT.matcher(s).replaceAll("$1"); return s; } /** * @return The remaining string and move the cursor to the end of the string */ public String readRemaining() { return this.read(this.remaining()); } /** * Read a word until the next whitespace character is found. * * @return The next word */ public String readWord() { return this.readUntil(' '); } /** * Read a string starting with a single or double quote.
* The quotes will be removed. * * @return The read string * @throws IllegalStateException If the end of the string is reached without finding a closing quote */ public String readString() { char start = this.require('"', '\'').read(); String s = this.readUntil(start, true); this.require(start).skip(); return s; } /** * Read a word or a string if the next character is a single or double quote. * * @return The read word or string * @throws IllegalStateException If the end of the string is reached without finding a closing quote (if a string is read) */ public String readWordOrString() { if (this.peek() == '"' || this.peek() == '\'') return this.readString(); return this.readWord(); } /** * Read a word and ensure that it is a valid integer number. * * @return The unparsed integer number */ public String readIntegerNumber() { String s = this.readWord(); if (!Util.INT_PATTERN.matcher(s).matches()) throw new IllegalStateException("Expected integer but got '" + s + "'"); return s; } /** * Read a word and ensure that it is a valid decimal number. * * @return The unparsed decimal number */ public String readDecimalNumber() { String s = this.readWord(); if (!Util.DECIMAL_PATTERN.matcher(s).matches()) throw new IllegalStateException("Expected decimal number but got '" + s + "'"); return s.replace(',', '.'); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy