while 循环语句中的扫描器函数导致运行时错误

Scanner function in while loop's statement causes runtime error

通过使用调试器,我设法找到了问题,但我不知道如何解决它。

导入java.util.*;

public class CreateString {

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder solution = new StringBuilder();
        while (scanner.hasNext()){
            Scanner inner_scanner = new Scanner(scanner.nextLine());
            String str = inner_scanner.next();
            while(inner_scanner.hasNextInt()) solution.append(str.charAt(inner_scanner.nextInt()));
            inner_scanner.close();
        }
        System.out.format("%d\n %s",solution.length(),solution);
        scanner.close();
    }
}

这就是我所说的 while 循环。这段代码的基本前提是我得到一个输入,首先是一个字符串,然后是几个数字。像这样:

some_string 0 5 1 4

在输出中,我写出了这些数字索引到的索引中的字符。所以我得到:

s_oe

问题是当它完成一个循环时,它会卡住并等待下一个输入。

假设您使用的所有循环和扫描仪都不是强制性的,如果我是您,我会按照以下方式进行操作:


解决方案 1:(未测试)

  • Scanner.nextXXX() 读取整行。所以some_string 0 5 1 4只会读到一个.nextLine()。为了那个原因:
    • 我阅读了 String str,
    • 然后将其拆分为 params。如果字符串 word 位于单元格 0,则后续单元格会将索引保留在参数中。
    • 我解析了int中的每个索引,然后在字符串中选择了相应的字符word
public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder solution = new StringBuilder();
        String str = scanner.nextLine();
        String[] params = str.split(" ");
        String word = params[0];
        String output = "";
        for(int i=1; i < params.length; i++) {
            int index = Integer.parseInt(params[i]);
            output += word.substring(index, index+1);
        }
}

解决方案 2:(未测试)

  • 在这里我等待参数作为应用程序的参数。所以他们将传递 main 方法的参数(String args)。看看这个 page
public static void main(String[] args) {
                
        String word = args[0];
        String output = "";
        for(int i=1; i < params.length; i++) {
            int index = Integer.parseInt(args[i]);
            output += word.substring(index, index+1);
        }
        System.out.println(output);
}

测试解决方案2:

javac Application.java
java Application some_string 0 5 1 4

解决方案 3(已测试)

现在我明白你的问题了。

这与您解释的完全一样。但是要停止你必须输入“exit”。

public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            String inputStr = scanner.nextLine();
            String[] params = inputStr.split(" ");
            String word = params[0];
            boolean stop = word.equals("exit"); // check if we need to stop
            
            while( ! stop ) {
                String output = "";
                for (int i = 1; i < params.length; i++) {
                    int index = Integer.parseInt(params[i]);
                    if(word.length() >= (index+1))
                        output += word.charAt(index); 
                }
                System.out.println(output); // print result

                // read params for next step
                inputStr = scanner.nextLine();
                params = inputStr.split(" ");
                word = params[0];
                stop = word.equals("exit"); // check if we need to stop
            }
        }

        System.out.println("Exit !");
}

scanner.hasNext() 将继续等待输入,直到到达 EOF 字符。我认为你唯一的选择是要么硬编码一个特殊字符来打破循环,要么按照这些行做一些事情:

public static void main(String[] args) {
    StringBuilder solution = new StringBuilder();
    try (Scanner scanner = new Scanner(System.in)) {
        String string = scanner.next();
        String[] indexes = scanner.nextLine().trim().split(" ");
        for (String index : indexes) {
            int parsedIndex = Integer.parseInt(index);
            if (parsedIndex >= 0 && parsedIndex < string.length()) {
                solution.append(string.charAt(parsedIndex));
            }
        }
        System.out.printf("%d\n%s", solution.length(), solution);
    }
}

只用一个Scanner:

    public static void main(String[] args) {
        var scanner = new Scanner(System.in);
        var solution = new StringBuilder();
        while (scanner.hasNextLine()){
            var str = scanner.next();
            while (scanner.hasNextInt()) {
                solution.append(str.charAt(scanner.nextInt()));
            }
            scanner.nextLine();
        }
        System.out.format("%d\n %s\n",solution.length(),solution);
    }

尽量不改变主要结构(太多)

但使用 hasNextInt() 将避免内循环在下一个标记出现之前完成 - 因此如果您需要为每个输入行一个输出,则需要另一种方法。

    public static void main(String[] args) {
        var scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            var solution = new StringBuilder();
            var str = scanner.next();
            var inner = new Scanner(scanner.nextLine());
            while (inner.hasNextInt()) {
                solution.append(str.charAt(inner.nextInt()));
            }
            inner.close(); 
            System.out.format("%d\n %s\n",solution.length(),solution);
        }
    }

或者,更好的是,使用 try-with resource,如 Alex

        var scanner = new Scanner(System.in);
        while (scanner.hasNextLine()){
            var solution = new StringBuilder();
            var str = scanner.next();
            try (var inner = new Scanner(scanner.nextLine())) {
                while (inner.hasNextInt()) {
                    solution.append(str.charAt(inner.nextInt()));
                }
            }
            System.out.format("%d\n %s\n",solution.length(),solution);
        }

在 Windows 上,您需要在自己的行上键入 Ctrl-Z,然后键入 Return 以结束标准输入(如果我是没有错)