有没有像“scanner.newLine();”这样的东西可以读取控制台输入的多行段落?

Is there such a thing as "scanner.newLine();" that could read a console input multi-line paragraph?

提问人:20GoodMen 提问时间:8/21/2023 更新时间:8/21/2023 访问量:51

问:

TLDR:我想将多行段落粘贴到控制台中(用于方法),但由于 .nextLine(),它只将第一行放入 String 变量中并忽略其余部分。

大家好, 我对 Java 很陌生,而且我只是完成了最基本的操作。我的术语仍然有点糟糕。我的任务是一个“解密器”方法,它接受一个“加密”的段落,在一个方法中交换字母,然后打印出“解密”版本:我的解密方法工作得很好。

问题出在用户输入上:我需要在控制台中放入一个“加密”的 7 行段落,它应该返回一个“解密”的 7 行段落。我使用了scanner.nextLine();这显然是行不通的。一旦出现换行符,扫描仪就会停止读取。 (我还注意到,如果您将包含多行的文本/段落复制粘贴到控制台中,控制台会将第一个换行符视为“Enter-Press”)

我真的没有找到任何适合我问题的解决方法。理想的情况是如果存在 scanner.newLine()。 再说一次,我不是很有经验,现在深感困惑和有点沮丧:,D

首先,我尝试通过删除“\n”“\r”“\n\r”并将其替换为“”来删除换行符

String text = scanner.nextLine();
        text = text.replaceAll("\n","");

这不起作用,因为无论如何,初始输入直到第一个换行符才被读取,因此“文本”中没有任何内容可以替换。 我尝试了一些阴暗的语法,例如“scanner.replaceAll(”\n“,”“).nextLine();”,这更像是一种绝望的行为。

有这个,我真的不明白:

public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    scanner.useDelimiter("\n");
    scanner.forEachRemaining(System.out::println);

我还发现了“输入你想输入多少行”循环方法,这种方法效果很好,但这不是任务的意义。

Java 文本 方法 控制台 java.util.scanner

评论


答:

1赞 rzwitserloot 8/21/2023 #1

为了给你提供正确的上下文,首先解释一些事情:

System.in实际上不是键盘。它是“过程的标准输入”,可以是任何东西。默认情况下,它只是“用户输入的任何内容”。例如,现在设置为文件的内容。包括它可以“用完”的概念(键盘永远不会)。java com.foo.MyApp <foo.txtSystem.infoo.txt

因此,当你写 时,这与告诉扫描仪不同:请给我所有东西,直到用户按下回车键。nextLine()

不,它是:给我所有东西,直到换行符出现在流中。如果是键盘,获取换行符的一种方法是按回车键。另一种方法是点击 CMD+V 或用于将数据粘贴到终端的任何内容,并且该数据包含换行符。从字面上看,没有办法区分这两件事。因此,没有方法可以去:“在用户按回车键之前,请给我所有文本”。因为这种方法如何运作?enterpress 看起来与粘贴数据中的换行符相同。“好的,这就是我想输入的全部内容,请继续处理它”的信号需要成为数据的一部分。如果它不是“换行符号”(因为你想捕获多段内容),那么你将不得不想出其他的东西来代替。System.inScanner

另外,是一种您永远不应该使用的损坏方法。它完全按照其规范所说的去做,但那不是你想象的那样。相反,这是毫无用处的东西。扫描仪将尽职尽责地继续成为这个无用的东西,它与扫描仪上的所有其他操作有各种令人惊讶的(阅读:不需要的)交互。nextLine()nextLine().next

相反,如果需要字符串输入,请使用,如果默认分隔符(即:任何空格,即如果您键入“Hello, World!”并按回车键,则第一个“token”是“Hello”,第二个是“World!”。如果您不希望这样做,请将分隔符设置为“换行符”。例如)。.next()

考虑到这一点:

这是一种方法:

System.out.println("Paste your paragraph, then hit enter and type 'DONE' and hit enter again:");
scanner.useDelimiter("(?i)\\RDONE\\R");
String data = scanner.next();
System.out.println("Your paragraph contains: " + data.length() + " symbols.");

这告诉扫描器,“分隔每个输入标记的东西”是一个换行符,然后是文本 DONE,然后是一个换行符(不同的操作系统使用不同的符号序列作为换行符,涵盖所有符号。 可能也有效,但适用于所有内容)。简单地说,该部件不区分大小写。\\R\n\\R(?i)DONE

论点是一个正则表达式,它是它自己的用于描述常规语法的迷你编程语言,这就是为什么它可能会让你觉得很奇怪,你可以坚持在那里,这意味着“不区分大小写”。我们真的在这些字符串引号中挤了一个小程序。.useDelimiter(?i)

评论

0赞 20GoodMen 8/21/2023
感谢您的深刻解释。我一定要进一步研究那个“迷你编程”。所以我现在用你的 .useDelimiter 版本尝试了它。而且它几乎可以很好地工作。我发现的唯一问题(我试图解决)是,一行的最后一个单词和另一行的下一个单词不再有空格。我试着用\s或:)的东西替换\n但总的来说,你给了我一个非常有教育意义的解决方案!谢谢!!!
0赞 Eldinur the Kolibri 8/21/2023 #2

有关所有技术细节,请参阅@rzwitserloot的惊人答案。我假设您真正想要的只是能够在控制台中复制/粘贴一段文本并在之后立即显示它。这可以通过以下不言自明的代码片段轻松完成:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder paragraph = new StringBuilder();
        
        System.out.println("Some Paragraph");
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            paragraph.append(line).append('\n');
        }
        System.out.println("Paragraph: " + paragraph);
    }
}

在这里,我们只是一个接一个地附加每一行。 如果要从控制台读取多行段落,而无需特定分隔符且不修改输入,则可以使用循环连续读取行,直到用户发出输入结束信号。这可以通过允许用户按特定的组合键(例如,或,取决于操作系统)来指示输入的结束来完成。Ctrl+DCtrl+Z

评论

0赞 user16320675 8/21/2023
或者只是var paragraph = new BufferedReader(new InputStreamReader(System.in)).lines().collect(Collectors.joining("\n"));
0赞 20GoodMen 8/21/2023
出于某种原因,我看到“line”变量随着每次循环迭代而上升(在调试器中),但代码之后就停止了......我复制了您的示例(将“段落”换成“文本”)然后我的方法: System.print.outln(encrypt(text.toString());它只是在 whileLoop 之后结束代码,尽管我看到循环将所有文本逐行存储在 StringBuilder“text”中......