当前位置: 首页 > 知识库问答 >
问题:

无法打印统一码字符,即使将打印字符串设置为 UTF-8

梁丘琛
2023-03-14

我目前的logClass有一个问题,无法打印umlauts“üäß”,我创建这个命令是为了将控制台上的每个字符串打印到JTextPane。

我已经在方法“控制台”上将PrintStream设置为使用“UTF-8”,并且我已经尝试了不同的字体,但是在尝试打印特殊字符时,我总是会出现错误字符。有人会对如何解决这个问题提出建议吗?

这是我的代码:

private JPanel logPanel;
private JScrollPane logScrollPanel;
private JTextPane textArea;
private Thread stdOutReader;
private Thread stdErrReader;
private boolean stopThreads;
private final PipedInputStream stdOutPin = new PipedInputStream();
private final PipedInputStream stdErrPin = new PipedInputStream();
private StyledDocument doc;
private Style style;

public void Console() {
    doc = (StyledDocument) textArea.getDocument();
    style = doc.addStyle("ConsoleStyle", null);
    StyleConstants.setFontFamily(style, "MonoSpaced");
    StyleConstants.setFontSize(style, 12);

    try {
        PipedOutputStream stdOutPos = new PipedOutputStream(this.stdOutPin);
        System.setOut(new PrintStream(stdOutPos, true, "UTF-8"));
    } catch (java.io.IOException io) {
        textArea.setText("Couldn't redirect STDOUT to this console\n" + io.getMessage());
    } catch (SecurityException se) {
        textArea.setText("Couldn't redirect STDOUT to this console\n" + se.getMessage());
    }

    try {
        PipedOutputStream stdErrPos = new PipedOutputStream(this.stdErrPin);
        System.setErr(new PrintStream(stdErrPos, true, "UTF-8"));
    } catch (java.io.IOException io) {
        textArea.setText("Couldn't redirect STDERR to this console\n" + io.getMessage());
    } catch (SecurityException se) {
        textArea.setText("Couldn't redirect STDERR to this console\n" + se.getMessage());
    }

    stopThreads = false; 
    stdOutReader = new Thread(this);
    stdOutReader.setDaemon(true);
    stdOutReader.start();

    stdErrReader = new Thread(this);
    stdErrReader.setDaemon(true);
    stdErrReader.start();
}

public synchronized void run() {
    try {
        while (Thread.currentThread() == stdOutReader) {
            try {
                this.wait(100);
            } catch (InterruptedException ie) {
            }
            if (stdOutPin.available() != 0) {
                String input = this.readLine(stdOutPin);
                StyleConstants.setForeground(style, Color.black);
                doc.insertString(doc.getLength(), input, style);
                textArea.setCaretPosition(textArea.getDocument().getLength());
            }
            if (stopThreads) {
                return;
            }
        }

        while (Thread.currentThread() == stdErrReader) {
            try {
                this.wait(100);
            } catch (InterruptedException ie) {
            }
            if (stdErrPin.available() != 0) {
                String input = this.readLine(stdErrPin);
                StyleConstants.setForeground(style, Color.red);
                doc.insertString(doc.getLength(), input, style);
                textArea.setCaretPosition(textArea.getDocument().getLength());
            }
            if (stopThreads) {
                return;
            }
        }
    } catch (Exception e) {
        textArea.setText("\nConsole reports an Internal error.");
        textArea.setText("The error is: " + e);
    }
}

private synchronized String readLine(PipedInputStream in) throws IOException {
    String input = "";
    do {
        int available = in.available();
        if (available == 0) {
            break;
        }
        byte b[] = new byte[available];
        in.read(b);
        input += new String(b, 0, b.length);
    } while (!input.endsWith("\n") && !input.endsWith("\r\n") && !stopThreads);
    return input;
}

共有1个答案

梁丘远航
2023-03-14

System.setout(新的打印流(标准输出,真,“UTF-8”));

这是不正确的。

"System out"不是"屏幕",而是一个抽象的概念:它是java应用程序的"标准out"。那是什么?嗯,你不知道。如果你的应用程序是用java-jar启动的myapp.jar

至关重要的是,“标准输出”,即抽象,从根本上说是基于字节的,而不是基于char的。因此,它是一个输出流(或者更确切地说,一个打印流,它只是一个比扎罗输出流)。不是写入器(写入器是输出流的字符变体)。

那么,当您只运行java-jarmyapp.jar,而不运行时,它是如何工作的呢?

嗯,你输入命令的shell会告诉操作系统启动应用程序,这样标准输出要么直接连接回shell,然后以某种方式处理它,要么将它连接到它本身当前也连接到的“控制台设备”。

从那里,java应用程序发送的字节(不是字符!请记住,它是基于字节的!)由该shell或tty处理。发送字节65,然后出现一个A

至关重要的是,shell/tty正在查看字节并必须将它们转换为字符。它的做法与所有将字节转换为字符或反之亦然的事情相同:使用字符集编码。

你必须回答的问题是:什么是字符集编码?-这是你必须指定的字符集编码,而不是UTF-8。因为将其设置为UTF_8意味着你写入打印流的字符通过UTF-8编码变成字节。如果tty使用CP1252将字节解码回字符,除了ASCII字符之外的所有内容都将变成mojibake。

除了java.nio.file中的内容外,java17之前的Javas将默认大多数字节到字符转换器。文件类转换为“平台本地编码”,通常您写入的tty使用的是平台本地编码。这意味着,在java17之前,您需要编写:System。setOut(new PrintStream(stdOutPos,true)),它就可以工作了。

但是,从java17(还是java18?)开始,一切都默认为UTF-8。因此,您必须编写这个残暴的灾难:

Charset nativeCharset = Charset.forName(System.getProperty("native.encoding", Charset.defaultEncoding().name());
Scanner sc = new Scanner(System.in, nativeCharset);
PrintStream out = new PrintStream(System.out, true, nativeCharset);

要求native.encoding属性是唯一的方法,但是在java17之前,系统属性不存在,所以我们必须回退到默认值(defaultEncode()从java17及更高版本一直是UTF-8,但它是java16及更早版本中的本机编码)。

如果这仍然不起作用,让你的tty告诉它它在字符集编码中使用什么,然后在你的java代码中也应用它。你怎么做?这取决于你使用的tty。在linux上,通常只是:键入set,点击回车键,然后检查各种环境变量,其中一个会提到它。

更复杂的是,通常当您在IDE中运行应用程序时,它们使用自己的字符集编码(通常是UTF-8),即使系统编码是其他编码native。据我所知,编码并不能解决问题。

解决所有这些问题的策略是使用控制台(System.getConsole()),但如果目标是让应用程序也能在IDE中执行,那么所有IDE……都无法实现它。

从本质上讲,从java应用程序将非ASCII写入控制台现在是一场灾难。

 类似资料:
  • 我正在使用dbf数据库和亚美尼亚字母,DBF编码是未知的,所以我创建了一个字母映射来解码复活的字符串。现在我有一个有效的Unicode字符串,但由于这个错误,我无法打印出来: UnicodeEncode 错误: “charmap” 编解码器无法对位置 0-5 中的字符进行编码:字符映射到 到目前为止我所尝试的: 怎么修

  • 问题内容: 我正在使用BeautifulSoup从HTML提取一些文本,但是我只是想不出如何正确地将其打印到屏幕(或与此相关的文件)上。 这是我的包含文本的类的样子: 当尝试打印一个实例时,这是我在控制台上看到的: 无论我尝试什么,都无法获得想要的输出(上面的文本应该是希伯来语)。我的最终目标是序列化到文件(使用json或pickle)并能够将其读回。 我在Ubuntu 10.10上使用Pytho

  • 问题内容: 这肯定是一件容易的事,但这确实困扰着我。 我有一个脚本,可以读取网页并使用Beautiful Soup对其 进行解析。我从 汤中 提取所有链接,因为我的最终目标是打印出link.contents。 我要解析的所有文本都是ASCII。我知道Python将字符串视为unicode,并且我确信这非常方便,在我的wee脚本中没有用。 每次我去打印一个包含’String’的变量时,我都会被打印到

  • 我想正确打印unicode(比如希腊字符),但我有问题。例如: 问题是是否有任何解决方案可以正确打印所有卡哈拉特。我认为对于希腊字符,UTF-16是可以的。

  • 问题内容: 我有一个已编码为UTF-8的俄语字符串 当我在Eclipse控制台中打印字符串时,我得到有人可以建议如何将俄语字符串打印到控制台,或者我在这里做错了什么? 我尝试过使用它将其转换为字节,然后仍然是同样的问题:-( 问题答案: 试试这个: 或这个: 俄语的主要问题是正确设置UTF-8编码。

  • #include <stdio.h> #include <wchar.h> int main(void) { char str1[] = "abcd"; wchar_t str2[] = L"abcd"; return 0; } 技巧 用gdb调试程序时,可以使用“x/s”命令打印ASCII字符串。以上面程序为例: Temporary brea