如何使用 Java 将 *abracadabra* 转换回字符串,就像 JavaScript decodeURIComponent(escape(x)) 一样?

How with Java to convert an *abracadabra* back to string like it does JavaScript decodeURIComponent(escape(x))?

我有一个字符串(十六进制每字节表示):

\xC3\x90\xC2\x9E\xC3\x91\xC2\x88\xC3\x90\xC2\xB8\xC3\x90\xC2\xB1\xC3\x90\xC2\xBA\xC3\x90\xC2\xB0\x20\xC3\x90\xC2\xB2\xC3\x90\xC2\xB0\xC3\x90\xC2\xBB\xC3\x90\xC2\xB8\xC3\x90\xC2\xB4\xC3\x90\xC2\xB0\xC3\x91\xC2\x86\xC3\x90\xC2\xB8\xC3\x90\xC2\xB8\x20\xC3\x90\xC2\xB0\xC3\x91\xC2\x82\xC3\x91\xC2\x80\xC3\x90\xC2\xB8\xC3\x90\xC2\xB1\xC3\x91\xC2\x83\xC3\x91\xC2\x82\xC3\x90\xC2\xBE\xC3\x90\xC2\xB2\x20\xC3\x90\xC2\xB4\xC3\x90\xC2\xBE\xC3\x90\xC2\xBA\xC3\x91\xC2\x83\xC3\x90\xC2\xBC\xC3\x90\xC2\xB5\xC3\x90\xC2\xBD\xC3\x91\xC2\x82\xC3\x90\xC2\xB0 [1]

看起来像这样:

ÐÑибка валидаÑии аÑÑибÑÑов докÑменÑа [2]

您可以使用http://0xcc.net/jsescape/查看。只需将十六进制序列粘贴到那里的 \xXX 字段中,该字符串将显示在 Plain text 字段中。

这个字符串 [2] 应该在(未知且明显错误的)编码后恢复。

如果(在同一网站 http://0xcc.net/jsescape/)您将从 Plain text 复制 abracadabra [2] 并将其粘贴到 Quoted-printable,你会在Plain text字段中看到解码后的:

Ошибка валидации атрибутов документа [3]

JavaScript by decodeURIComponent(escape(x)) 也可以完成相同的操作,其中 x 包含 abracadabra 字符串 [2].

所以我的问题是:如何使用 [=50] 从 abracadabra [2] 恢复 original 字符串 [3] =] ?

谢谢

字符串包含字符,其中字符是两个字节的 UTF-16 值。字节、二进制数据、保存文本必须与编码相关联,因为 String 保存 Unicode。 Java 明确区分了 bytechar

用正则表达式替换一个可以手动转换为:

    byte[] arr = {(byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0x9E, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x88, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB8, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB1, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBA, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB0, (byte) 0x20, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB2, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB0, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBB, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB8, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB4, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB0, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x86, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB8, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB8, (byte) 0x20, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB0, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x82, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x80, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB8, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB1, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x83, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x82, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBE, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB2, (byte) 0x20, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB4, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBE, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBA, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x83, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBC, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB5, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xBD, (byte) 0xC3, (byte) 0x91, (byte) 0xC2, (byte) 0x82, (byte) 0xC3, (byte) 0x90, (byte) 0xC2, (byte) 0xB0};
    String s = new String(arr, StandardCharsets.UTF_8);

翻译带有反斜杠、x 和两个十六进制数字的 ASCII 文本必须为:

    String t = "\xC3\x90\xC2\x9E\xC3\x91\xC2\x88\xC3\x90\xC2\xB8\xC3\x90\xC2\xB1\xC3\x90\xC2\xBA\xC3\x90\xC2\xB0\x20\xC3\x90\xC2\xB2\xC3\x90\xC2\xB0\xC3\x90\xC2\xBB\xC3\x90\xC2\xB8\xC3\x90\xC2\xB4\xC3\x90\xC2\xB0\xC3\x91\xC2\x86\xC3\x90\xC2\xB8\xC3\x90\xC2\xB8\x20\xC3\x90\xC2\xB0\xC3\x91\xC2\x82\xC3\x91\xC2\x80\xC3\x90\xC2\xB8\xC3\x90\xC2\xB1\xC3\x91\xC2\x83\xC3\x91\xC2\x82\xC3\x90\xC2\xBE\xC3\x90\xC2\xB2\x20\xC3\x90\xC2\xB4\xC3\x90\xC2\xBE\xC3\x90\xC2\xBA\xC3\x91\xC2\x83\xC3\x90\xC2\xBC\xC3\x90\xC2\xB5\xC3\x90\xC2\xBD\xC3\x91\xC2\x82\xC3\x90\xC2\xB0";
    Matcher m = Pattern.compile("\\x(..)").matcher(t);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    while (m.find()) {
        baos.write(Integer.parseInt(m.group(1), 16));
    }
    s = baos.toString(StandardCharsets.UTF_8);

在这两种情况下,原始字节都被解码为 UTF-8。但是字符串仍然是 “编码。”实际上它是两次 UTF-8 编码,一个错误,不能保证 unencoding/decoding 是可能的。

黑客反编码是将每个字符解释为字节。为此使用单字节编码。有标准提供的字符集 ISO-8859-1。

    byte[] arr2 = s.getBytes(StandardCharsets.ISO_8859_1);
    s = new String(arr2, StandardCharsets.UTF_8);

    System.out.println(s);

现在输出是可读的

Ошибка валидации атрибутов документа

这具有讽刺意味的意思是“验证文档属性时出错。”