Java Scanner for peeking something (int, double, line, etc) without advancing position

时间:2017-06-14 10:29:38

标签: java java.util.scanner bufferedreader inputstreamreader

We know that nextInt(), nextDouble(), nextLine(), etc methods of Java Scanner class parses something (int, double, line, etc) and advances the position of the scanner. But I need a way only for parsing something but not for advancing the position. That means, I need some way for something like peekInt(), peekDouble(), peekLine(), etc methods.

Here is an example for why it may be necessary. Suppose, I have an abstract class Server which has an abstract method respond(Scanner in, PrintWriter out, String clientIp) to be implemented by other classes. Here is the portion of code:

public abstract class Server {
    // ... (some initialization variables)

    public static final String endSocketMarker = "END";

    public final void runServer() {
        // ... (multithreading code)

        clientSocket = serverSocket.accept();
        Scanner in = new Scanner(new BufferedReader(new InputStreamReader(clientSocket.getInputStream())));
        PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);

        String clientIp = in.nextLine();
        String marker = "";
        do {
            respond(in, out, clientIp); // call abstract method
            marker = in.nextLine(); //TODO: find a way so that input line is peeked (but not skipped)
        } while(!marker.equals(endSocketMarker));

        // ... (close client socket)
    }

    protected abstract void respond(Scanner in, PrintWriter out, String clientIp);

    // ... (other methods)
}

Here marker = in.nextLine(); parses the line until a line separator found and then advances the position to the beginning of the next line. If marker.equals(endSocketMarker) is false, then the string assigned in marker cannot be read inside respond(in, out, clientIp) method at all. It must be avoided somehow. I may pass the variable marker into respond(in, out, clientIp), but it will make the code cluttered.

Is there any better way for achieving my goal?

2 个答案:

答案 0 :(得分:0)

java.util.Scanner.hasNext()方法如果此扫描器的输入中有另一个标记,则返回true。在等待输入扫描时,此方法可能会阻塞。扫描仪不会超过任何输入。

这里有一个例子, hasNext() example

答案 1 :(得分:0)

您可以通过带有相应 hasNextPattern 检查下一个令牌来完成此操作。这样您就不会推进位置,但您可以查看下一个令牌(通过其模式)...

import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
import java.util.regex.Pattern;

public class Main {
    
    public static void main(final String[] args) {
        final Charset charset = StandardCharsets.UTF_8;
        final String endSocketMarker = "END";
        final String testString = "This is some test text.\n1234567890\n" + endSocketMarker + "\nThis is still writing...";
        final Scanner scan = new Scanner(new ByteArrayInputStream(testString.getBytes(charset)), charset.name());
        final Pattern endPattern = Pattern.compile(Pattern.quote(endSocketMarker));
        while (!scan.hasNext(endPattern))
            System.out.println("Processing input, with first line being: \"" + scan.nextLine() + "\".");
        System.out.println("Reached the \"" + scan.nextLine() + "\".");
    }
}

testString 转换为提供给 InputStreamScanner 的目的只是为了演示如何将 InputStreamScanner 一起使用.否则,我可以简单地将 testString 直接提供给 Scanner 的构造函数。


我还考虑为 Scanner 提供 BufferedInputStream 并在后者上使用 mark/reset,但经过一些测试和一些搜索后,我发现 Scanner 在内部使用缓冲区。这意味着 Scanner 的缓冲区被来自 BufferedInputStream 的所有数据填满,因此在不让我们标记正确位置的情况下推进 BufferedInputStream 的位置。即使您每次都创建一个新的 Scanner 对象,使用相同的 BufferedInputStream 也会产生相同的效果,因为 BufferedInputStream 无论如何都会被推进。