【问题标题】:How to suppress or remove escape code characters from Java stdin on Linux terminal如何在 Linux 终端上从 Java 标准输入中抑制或删除转义码字符
【发布时间】:2019-01-30 06:58:58
【问题描述】:

我在这里和其他地方对这个问题的主题进行了一些研究,我发现了 jline3,它似乎是一个明确的解决方案,并提供了大量重要的跨平台优势和功能。

但是,为了更好地理解 Java 如何使用流读取器和输入(包括原始字节),以及在 Linux 终端中实现基本的基于文​​本的冒险游戏,我希望能够抑制或根据用户输入从stdin 中删除箭头键转义码。

这似乎无法通过Scanner 实现,而且我不确定如何使用 Java 将终端置于原始输入模式 - 如果有办法通过 shell 脚本实现它,我'到目前为止,我一直无法弄清楚。我正在使用一个基本的 shell 脚本来调用我的 Java 程序并传入一些系统属性,所以这也是一个很好的解决方案。

到目前为止,我已经使用了ByteBufferCharBufferDecoder 等的组合,我从其他问题和一些初步研究中看到了这些,但无法实现我的目标'我正在寻找。

我怎样才能让我的 Java 程序等待用户输入而不显示或捕获箭头键转义字符(例如,^[[A^[[B)?

感谢您提供任何帮助或其他资源。

编辑/更新:

感谢所有对此问题的回复。最终,我正在研究一个几乎完全符合我想要的解决方案,它结合了 Java Console 类及其正则表达式功能。

一个非常基本的框架如下。本质上,我选择了 exclude all, include some 方法,其中所有字符都被禁止,但我编译成 Pattern 的字符允许打印到屏幕上。

这也让我可以测试其他重要的输入键,例如 Enter 以进入和退出游戏的 命令模式,因为我希望游戏对“移动”键做出反应并让用户能够按 Enter 并输入一些命令。

我不得不摆弄stty 以允许这个解决方案,并且Java 应用程序是通过一个bash 脚本启动的。

Bash 脚本:

#!/bin/bash

# Save current terminal settings
STTY_SAVE=$(stty -g)

# Disable need to press [Enter] in order to have input processed
stty cbreak
# Disable the echoing of input
stty -echo
# Tell the terminal that erasure on the console should produce a backspace cursor movement
stty erase ^H

# Execute application
java reader_testing.Main

# Restore saved terminal settings
stty $STTY_SAVE
exit 0

注意:stty erase ^H 似乎也允许 Java 中的 Console 在 *nix 操作系统上捕获退格键字符代码 \010。如果没有该行,它似乎会执行删除(?)

Java 代码

Console console = System.console();    

int symbol = 0;
char character = 0;

String matchString = new String();
StringBuilder input = new StringBuilder();

Pattern allowed = Pattern.compile( "[a-z0-9 !@#$%^&*()_+-=]" );
Matcher matcher = null;

while ( true ) { // This is an arbitrary loop for the example
    try {
        symbol = console.reader().read();

        if ( symbol == 10 ) { // 10 = Enter
            break;
        }

        character = (char) symbol;

        matchString = Character.toString( character );

        matcher = allowed.matcher( matchString );

        if ( matcher.find() ) {
            input.append( character );

            System.out.print( "\r" + input );
        }
    } catch ( IOException e ) {
        e.printStackTrace();
    }
}

System.out.println( "\nYou entered: " + input );

问题:

  1. 仍在研究退格功能,用“空”字符(例如,char c = 0;)重写输入 StringBuilder 对象的字符并调整其大小。这最终可能根本不起作用。

    李>
  2. 我无法找到一种方法来排除大写字母 A、B、C 和 Ds,它们遵循代表箭头键的转义码序列,因此我不得不禁止所有大写字母。我试图等到阅读器检测不到更多输入,然后解析该输入,但未能成功实现。

  3. Insert 和 Delete 等特殊键生成的字符代码包括仍会打印的数字。我还不确定如何在不禁止数字的情况下防止这种情况发生(与箭头键和大写字母的问题相同)。

最后,这些都可能不起作用或者会受到相当的限制,但是玩这个很有趣,如果情况更糟,我可以让退格键清除整个输入字符串。输入命令不是游戏的主要方面。

【问题讨论】:

    标签: java terminal stdin


    【解决方案1】:

    您可以使用 java.io.Console 类。 Console.writer() 自动处理底层字符编码。 Console.readLine() 从用户那里检索一行文本,并等到他按 Enter 键终止。还有很多其他方法可以帮助您制作命令行游戏。

    【讨论】:

    • 感谢控制台的建议,不幸的是,在提示符下按箭头键时,我仍然可以看到箭头键转义码(例如,^[[A)。
    【解决方案2】:

    根据您的需要更改正则表达式以接受您认为正确或错误的内容。

    public class PasscodeScanner {
    
     public static void main(String args[]) {
    
        Scanner key = new Scanner(System.in);
        while(getInput(key)) {
            //keep doing until we you're good
        }
        System.out.println("Congrats, you're good.");
    }
    
    private static boolean getInput(Scanner key) {
        System.out.print("Enter your passcode: ");
        String sentence = key.nextLine();
        if(validate(sentence)) {
            System.out.println("You are cleared");
            return false;
        }
        return true;
    }
    
    private static boolean validate(String entered) {
        //change regex as per your need
        Pattern pattern = Pattern.compile("[a-z]");
        Matcher matcher = pattern.matcher(entered);
        if (matcher.find()) {
            return true;
        }
        return false;
    }
    }
    

    【讨论】:

    • 这是一个很好的解决方案,它使用 Pattern 和 Matcher 来有效地验证某些输入,而忽略任何 shell 转义码。不幸的是,当我按下任何箭头键时,我可以在提示符处看到转义码 - 我希望那些不会出现在提示符中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多