Java Scanner 用于在不前进位置的情况下查看某些内容(int、double、line 等)

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

提问人:arnobpl 提问时间:6/14/2017 更新时间:4/14/2021 访问量:1072

问:

我们知道 Java 类的 、 、 等 方法解析某些东西(int、double、line 等)并推进扫描器的位置。但我只需要一种方法来解析某些东西,而不是为了提升位置。这意味着,我需要一些方法来实现诸如 、 、 等方法。nextInt()nextDouble()nextLine()ScannerpeekInt()peekDouble()peekLine()

下面是一个示例,说明为什么可能需要这样做。假设,我有一个抽象类,它有一个由其他类实现的抽象方法。下面是代码的一部分:Serverrespond(Scanner in, PrintWriter out, String clientIp)

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 解析该行,直到找到行分隔符,然后将该位置推进到下一行的开头。如果为 false,则在方法中根本无法读取 中分配的字符串。必须以某种方式避免它。我可能会将变量传递给 ,但它会使代码变得混乱。marker = in.nextLine();marker.equals(endSocketMarker)markerrespond(in, out, clientIp)markerrespond(in, out, clientIp)

有没有更好的方法来实现我的目标?

java.util.scanner bufferedreader inputstreamreader

评论

0赞 parsecer 5/9/2020
同样的问题,你解决了吗?
0赞 arnobpl 5/9/2020
@parsecer:API 没有为此提供任何内容。据我所知,我不得不手动处理。

答:

0赞 cmb28 6/14/2017 #1

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

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

评论

1赞 arnobpl 6/14/2017
hasNext()如果扫描程序的输入中有另一个令牌,但不返回该令牌,则方法返回 true。但是我需要该令牌,而无需推进扫描仪的位置。我想,我无法向你解释我的问题。
0赞 cmb28 6/14/2017
扫描程序不会越过该令牌,而是停留在那里。
0赞 arnobpl 6/14/2017
所有包含(例如,,)的方法都会推进扫描程序的位置,否则对于连续方法调用,将始终返回相同的字符串。这是一行“位置设置为下一行的开头”。其他方法也类似。nextnextInt()nextDouble()nextLine()
0赞 gthanop 4/14/2021 #2

为此,您可以通过 a 和相应的 hasNext 检查下一个令牌。这样你就不会推进仓位,但你可以窥视下一个代币(通过它的模式)......Pattern

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() + "\".");
    }
}

将 转换为提供给 的 的意义只是为了演示如何将 与 一起使用。否则,我可以简单地直接向 的构造函数提供。testStringInputStreamScannerInputStreamScannertestStringScanner


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