在Java中将Windows-1252转换为UTF-16

3

我正在尝试将所有的Windows特殊字符转换为它们的Unicode等价物。我们有一个Flex应用程序,用户保存一些富文本,然后通过Java Emailer发送电子邮件给收件人。但是,我们一直遇到Word中的特殊字符,在电子邮件中只显示为问号。

目前为止,我已经尝试过:

 private String replaceWordChars(String text_in) {
    String s = text_in;

    // smart single quotes and apostrophe
    s = s.replaceAll("[\\u2018|\\u2019|\\u201A]", "\'");
    // smart double quotes
    s = s.replaceAll("[\\u201C|\\u201D|\\u201E]", "\"");
    // ellipsis
    s = s.replaceAll("\\u2026", "...");
    // dashes
    s = s.replaceAll("[\\u2013|\\u2014]", "-");
    // circumflex
    s = s.replaceAll("\\u02C6", "^");
    // open angle bracket
    s = s.replaceAll("\\u2039", "<");
    // close angle bracket
    s = s.replaceAll("\\u203A", ">");
    // spaces
    s = s.replaceAll("[\\u02DC|\\u00A0]", " ");

    return s;

这个方法是可行的,但我不想手动将所有Windows-1252字符编码为它们相应的UTF-16字符(假设默认的Java字符集是UTF-16)。

然而,我们的用户不断发现Microsoft Word中有更多的字符,Java无法处理。因此,我进行了搜索,并找到了以下示例:

private String replaceWordChars(String text_in) {
    String s = text_in;
    try {
        byte[] b = s.getBytes("Cp1252");
        byte[] encoded = new String(b, "Cp1252").getBytes("UTF-16");
        s = new String(encoded, "UTF-16");


    } catch (UnsupportedEncodingException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return s;

但是当我在Eclipse调试器中观察编码时,没有任何变化。
处理Microsoft与Java之间的编码问题肯定有简单的解决方案。
有什么想法吗?

1
在第一种情况下,您只是用ASCII字符替换非ASCII字符。您根本没有改变编码。在第二个代码片段中,您实际上什么也没做,除了将所有无法由Cp1252处理的字符转换为“?” - Jon Skeet
好的@JonSkeet,您认为将所有非ASCII字符替换为它们的ASCII等效字符如何? - idonaldson
@CodingGuy 并非所有的非 ASCII 字符都有 ASCII 等价物... ASCII 只有不到 128 个字符,而 Unicode 则有超过 100,000 个字符。你只需要弄清楚如何正确发送电子邮件即可。发送的电子邮件采用什么编码方式?应该使用 UTF-8 编码,这样就不必删除非 ASCII 字符了。 - bames53
那么,邮件发送程序或生成电子邮件文本的程序存在其他问题,因为在UTF-8电子邮件中没有理由将特殊字符转换为“?”。 - bames53
听起来他正在使用一个读取器读取“Cp1252”数据,而该读取器设置为使用“UTF-8”编码,这会导致与不兼容字符相关的类似有趣的行为(那些其“Cp1252”编码与其“UTF-8”编码不同的字符)。 - Shadow Man
显示剩余2条评论
3个回答

4
你可以尝试使用 java.nio.charset.Charset
final Charset windowsCharset = Charset.forName("windows-1252");
final Charset utfCharset = Charset.forName("UTF-16");
final CharBuffer windowsEncoded = windowsCharset.decode(ByteBuffer.wrap(new byte[] {(byte) 0x91}));
final byte[] utfEncoded = utfCharset.encode(windowsEncoded).array();
System.out.println(new String(utfEncoded, utfCharset.displayName()));

2
请按照以下步骤操作:
  1. 使用源文件的编码(Windows-1252)创建一个InputStreamReader
  2. 使用目标文件的编码(UTF-16)创建一个OutputStreamWriter
  3. 将从读取器中读取的信息复制到写入器中。您可以使用BufferedReaderBufferedWriter逐行写入内容。
因此,您的代码可能如下所示:
public void reencode(InputStream source, OutputStream dest,
        String sourceEncoding, String destEncoding)
        throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(source, sourceEncoding));
    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(dest, destEncoding));
    String in;
    while ((in = reader.readLine()) != null) {
        writer.write(in);
        writer.newLine();
    }
}

当然,这不包括try / catch部分,并将其委托给调用者。

如果你只是想要以某种字符串形式获取内容,则可以将writer替换为StringWriter并返回其toString值。然后,您不需要目标流或编码,只需要一个地方来存放字符:

public String decode(InputStream source, String sourceEncoding)
        throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(source, sourceEncoding));
    StringWriter writer = new StringWriter();
    String in;
    while ((in = reader.readLine()) != null) {
        writer.write(in);
        writer.write('\n'); // Java newline should be fine, test this just in case
    }
    return writer.toString();
}

为什么要点踩?没有代码吗?我现在就写。请先评论,待会再点踩。 - Brian
第一步行不通。这是来自 Web 上的 Flex RIA。用户很可能会在 Word 中键入他们漂亮的电子邮件,然后将其复制粘贴到我们的应用程序中并发送电子邮件。我会尝试使用 Streams 看看会发生什么。 - idonaldson
我刚刚推荐了它。我正在编写的代码实际上只是使用流。更好的是,我会在我的编辑中包含它。 - Brian
我不是那个点踩的人,似乎那个词只适用于桌面应用程序? - idonaldson
好的,请看我的更新 :) 这应该给你一个开始的方向。 - Brian
此外,如果您只是想将内容作为某种字符串获取,可以使用 StringWriter 替换 writer 并返回其 toString 值。然后您就不需要目标流或编码,只需要一个地方来存储字符即可。 - Brian

1

到目前为止,我测试过的所有东西似乎都有效:

private String replaceWordChars(String text_in) {
    String s = text_in;
    
    final Charset windowsCharset = Charset.forName("windows-1252");
    final Charset utfCharset     = Charset.forName("UTF-16");
    
    byte[] incomingBytes = s.getBytes();
    final CharBuffer windowsEncoded = 
        windowsCharset.decode(ByteBuffer.wrap(incomingBytes)); 
    
    final byte[] utfEncoded = utfCharset.encode(windowsEncoded).array();
    s = new String(utfEncoded);
    
    return s;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接