在hasNext()返回false之后更改Scanner的输入

时间:2019-10-05 04:36:26

标签: java

我正在使用自定义的InputStream for Scanner,并希望对其进行更改。但是在第一次读取并更改InputStream中的数据后,它会停止。

我可以修改我的代码以进行二读吗?哪种方式?

更新我将此代码与其他程序一起使用,并将其标准输入重定向到我的。因此,我需要更改System.in,并且无法重新创建扫描仪。

这是我的课程:

class CRStream extends InputStream {
  private ByteArrayInputStream in;
  public synchronized int read() throws IOException {
     int x = in.read();
    return x;
  }
  public synchronized int read(byte[] bytes, int off, int len) throws IOException {
    return in.read(bytes, off, 1);
  }
  public void set(String utf8str) throws IOException{
     try{
        in = new ByteArrayInputStream(utf8str.getBytes(StandardCharsets.UTF_8.name()));
    }
    catch (UnsupportedEncodingException e){}
  }
}

和使用示例

public class Main {
    public static void main(String[] args) throws IOException {
         CRStream in = new CRStream();
         System.setIn(in);
         Scanner scanner = new Scanner(System.in);
         //Everything is OK
         in.set("Word1 Ok Word2 Ok");
         while (scanner.hasNext()){
             System.out.println(scanner.next());
         }
         //Does not work... Prints nothing
         in.set("WORD3 Ok WORD4 Ok");
         while (scanner.hasNext()){
             System.out.println(scanner.next());
         }
    }
}

这是第二个例子

一个简单的客户端程序

class ClientProgram {
    public static Scanner in = new Scanner(System.in);
    public static void main(String[] args) {
        System.out.println(in.next());
    }
}

我用代码对其进行测试

public class Main {
    public static void main(String[] args) {
         CRStream in = new CRStream();
         System.setIn(in);
         in.set("Test1");
         ClientProgram.main(new String[0]);
         in.set("Test2");
         ClientProgram.main(new String[0]);

    }
}

它在第二次测试中落在NoSuchElementException上。

3 个答案:

答案 0 :(得分:0)

奇怪的是,当扫描程序可以直接从字符串中读取内容时,为什么要跳这么多圈呢?

public static void main(String[] args) throws IOException {

     Scanner scanner = new Scanner("Word1 Ok Word2 Ok");
     while (scanner.hasNext()){
         System.out.println(scanner.next());
     }

     scanner = new Scanner("WORD3 Ok WORD4 Ok");
     while (scanner.hasNext()){
         System.out.println(scanner.next());
     }

如果您希望Ok成为分隔符,则可以在扫描仪上调用useDelimiter(" Ok ")

对于实际问题,我怀疑内部扫描仪可能正在缓冲您的输入流,而没有意识到您已对其进行了切换。也许还是要制作新的扫描仪,或者将您的crinputstream重置()。也不需要用您的系统替换输入流,然后将扫描仪连接到系统中。扫描程序无需通过system.in

即可从您的输入流中读取

答案 1 :(得分:0)

您可能应该包装所有获得的输入,而不是实施一个新奇的InputStream,而只需返回要解析的字符串。这样,您的包装器类可以根据当前正在读取的内容来维护使用的Scanner

class TokenProvider {
    Queue<Scanner> readFrom = new Deque<Scanner>();
    Scanner currentScanner;

    public void addSource(String string) {
        readFrom.add(new Scanner(string));
    }
    public boolean hasNext() {
        nextScanner();
        return currentScanner != null && currentScanner.hasNext();        
    }
    public String next() {
        return currentScanner.next();
    }
    private void nextScanner() {
        while (currentScanner == null || !currentScanner.hasNext()) {
            if (readFrom.isEmpty()) break;
            currentScanner = readFrom.poll();
        }
    }
}

现在您的驱动程序代码如下

 TokenProvider in = new TokenProvider();
 in.addSource("Word1 Ok Word2 Ok");
 while (in.hasNext()){
     System.out.println(in.next());
 }
 // all data has been iterated, but we can add more now
 in.addSource("WORD3 Ok WORD4 Ok");
 while (in.hasNext()){
     System.out.println(in.next());
 }

答案 2 :(得分:0)

扫描器保持内部状态,一旦当前源用尽,则设置标志“ sourceClosed = true”。由于将来扫描器认为尽管更改了源流,它仍然是空的,所以以后对该扫描器的任何访问都将被拒绝,因为该标志不会回滚。如果没有定制的扫描仪实现,我看不出有一种方法来规避这一问题。如果可能的话,请尝试使用新的Scanner进行每次读取,而不是进入那个兔子洞。

在第二个客户端中,不要维护静态扫描仪,

class ClientProgram {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.println(in.next());
    }
}