Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
196 views
in Technique[技术] by (71.8m points)

string - (Java) Character 'é' is displayed wrong in JTextArea

first time posting something and I have a question.

I'm using JFrame and JTextArea, redirecting my console output into the JTextArea. In the console it shows correctly. This is the code of redirecting:

public PrintStream redirectOut() {
    
    OutputStream out = new OutputStream() {
        @Override
        
        public void write(int b) throws IOException {
            String k = String.valueOf((char) b);
            byte[] o = k.getBytes();
            String text = new String(o,"Cp1252");
            output.append(k);
        }
    };
    PrintStream ps = new PrintStream(out);
    System.setOut(ps);
    System.setErr(ps);
    return ps;
}

If i put the character 'é' the same way into the TextArea it shows correctly, but not like this. Why is that? Someone has a solution? (output is my JTextArea) Thanks!

question from:https://stackoverflow.com/questions/65938143/java-character-%c3%a9-is-displayed-wrong-in-jtextarea

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It’s not quite clear what your multi-step conversion is trying to achieve.

The write(int) method will receive a single byte, for some reasons passed as int. Since the byte originates from a PrintStream constructed as new PrintStream(out), it will be encoded in the system’s default encoding.

One way to convert it back to a String using the same (system default) encoding would be

byte[] array = { (byte) b };
String text = new String(array);

However, there are some things to keep in mind

  1. The system default encoding might not support all unicode characters. Hence, the code above is correct, but still may cause data loss. You should therefore not rely on the system default encoding, but use an explicit encoding capable of handling all characters, e.g. UTF-8, for both sides.

  2. This approach can’t handle multi-byte encodings as when trying to convert a single byte of a multi byte sequence back to a string you’ll end up at invalid or wrong characters. A portable program can not assume to know whether the system default encoding is multi-byte or not. When following the advice of point 1, you’ll always end up at a multi-byte encoding. You need a solution that can accumulate multiple bytes before converting them to a string. That will even improve the efficiency.

Here is a complete solution:

public class PrintToTextArea extends ByteArrayOutputStream implements Runnable
{
  public static PrintStream create(JTextArea ta)
  {
    try
    {
      return new PrintStream(new PrintToTextArea(ta), true, "UTF-8");
    }
    catch(UnsupportedEncodingException ex)
    {
      throw new AssertionError("UTF-8 should always be supported", ex);
    }
  }

  private final JTextArea target;

  private PrintToTextArea(JTextArea ta)
  {
    super(100);
    target = ta;
  }
  @Override
  public void flush()
  {
    if(EventQueue.isDispatchThread()) run(); else EventQueue.invokeLater(this);
  }
  @Override
  public synchronized void run()
  {
    target.append(new String(buf, 0, count, StandardCharsets.UTF_8));
    count = 0;
  }
}

It uses UTF-8 on both sides, to handle all unicode characters, and gathers bytes in the buffer of a ByteArrayOutputStream, to create a new String and append it when flush is called, which happens automatically on newlines or when flush has been called explicitly.

You can try it with something like

public static void main(String[] args) {
  try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); }
  catch(ReflectiveOperationException | UnsupportedLookAndFeelException ex) {}

  JFrame f = new JFrame();
  JTextArea ta = new JTextArea(40, 60);
  f.setContentPane(new JScrollPane(ta));
  PrintStream ps = PrintToTextArea.create(ta);
  System.setOut(ps);
  System.setErr(ps);
  f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  f.pack();
  f.setVisible(true);

  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  Thread.dumpStack();
  System.out.println("è");
  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  System.out.println("??ü");
  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
  System.out.println("u263a   ud83dude80");
  LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...