vendredi 30 novembre 2018

Get Java Scanner Input Without Advancing Scanner

Get out the value of the scanner without advancing it - Java

I want to get the value of the input in the scanner without advancing it. Currently, I am using my scanners input as System.in.

final var sc = new Scanner(System.in);

I know of the hasNext methods on scanner, and they are currently my best/only way to check its input without advancing it.

Here is how I ensure a positive integral input from sc for example.

public static int getPositiveIntegerInput(Scanner sc) {
    System.out.println("Please input a positive integer");
    sc.useDelimiter("\n");
    while (!sc.hasNextInt() || sc.hasNext(".*[^\\d].*")) {
        System.out.println("Invalid input, please try again");
        sc.nextLine();
    }
    return sc.nextInt();
}

I want to extend this notion of checking sc's input without advancing it to actually getting sc's input without advancing it.

What I have tried to to this point

I have gone through the implementation details of hasNext() on Scanner.

Implementation of hasNext:

public final class Scanner {

    public boolean hasNext(Pattern pattern) {
        ensureOpen();
        if (pattern == null)
            throw new NullPointerException();
        hasNextPattern = null;
        saveState();
        modCount++;

        while (true) {
            if (getCompleteTokenInBuffer(pattern) != null) {
                matchValid = true;
                cacheResult();
                return revertState(true);
            }
            if (needInput)
                readInput();
            else
                return revertState(false);
        }
    }
}

It seemed to me at least, that one can get scanner's input from the method getCompleteTokenInBuffer, but truly I don't really understand how it works. I don't know if that method alone gets the value of scanner without advancing it, or if it advances it then something else reverts it back to the state it was in before the input as if it has not advanced at all, or if it gets it in combination with something else, or really how at all.

I have been playing around with invoking the private methods Scanner through Java's reflection API, to try to actually return the token holding sc's input value without actually advancing methods (but to be honest, I'm just playing around with it and don't know how to actually accomplish what I want to do).

public static void main(String[] args) {

    final var sc = new Scanner(System.in);
    sc.useDelimiter("\n");

    var str = "";

    try {
        Method method = Scanner.class.getDeclaredMethod("getCompleteTokenInBuffer", Pattern.class);
        method.setAccessible(true);
        str = (String) method.invoke(sc, Pattern.compile(".*"));
    } catch (Exception e) {
        System.out.println("Well, that didn't work!");
        System.out.println("Exception: " + e);
    }

    System.out.println("getCompleteTokenInBuffer: " + str);

    // Prints: "getCompleteTokenInBuffer: null"
}

Note: The method above does not wait for an input before get the value of sc's input and hence returns a value of null.

Goal:

Just to reiterate, I would like to find away to capture and return a Scanner object's input value with actually advancing it.





Aucun commentaire:

Enregistrer un commentaire