如何使用 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 明确区分了 byte
和 char
。
用正则表达式替换一个可以手动转换为:
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);
现在输出是可读的
Ошибка валидации атрибутов документа
这具有讽刺意味的意思是“验证文档属性时出错。”
我有一个字符串(十六进制每字节表示):
\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 明确区分了 byte
和 char
。
用正则表达式替换一个可以手动转换为:
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);
现在输出是可读的
Ошибка валидации атрибутов документа
这具有讽刺意味的意思是“验证文档属性时出错。”