Python中的Java修改后的UTF-8字符串

8
我正在通过Python与Java应用程序进行接口交互。我需要能够构建包含UTF-8字符串的字节序列。Java在DataInputStream.readUTF()中使用修改后的UTF-8编码,而Python不支持(至少目前)。有人可以指导我如何在Python中构建Java修改后的UTF-8字符串吗?
更新#1:要了解更多关于Java修改后的UTF-8,请查看DataInput接口上第550行的readUTF()方法此处,或者Java SE文档中的此处
更新#2:我正在尝试与第三方JBoss Web应用程序进行接口交互,该应用程序使用此修改后的UTF-8格式通过调用DataInputStream.readUTF()从POST请求中读取字符串(对于任何有关正常Java UTF-8字符串操作的困惑,我很抱歉)。

1
“modified UTF-8”是什么意思?据我所知,如果你要求Java进行UTF-8编码,它会使用完全标准的UTF-8。但请注意,Java的本地字符串格式是UTF-16。 - Jon Skeet
2
有一些关于UTF-8的信息可以在维基百科上找到:http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8(因此,涉及序列化、JNI和类内字符串常量)。 - McDowell
1
我建议修改 Java 应用程序以使用真正的 UTF-8。 - Tom Hawtin - tackline
谢谢McDowell,我正在尝试与一个使用修改后的UTF8格式通过POST请求读取字符串的JBoss Web应用程序进行接口交互。 - QAZ
好的,那是一种非常特定的序列化格式 - 这与暗示Java总体上破坏UTF-8相当不同。 - Jon Skeet
显示剩余3条评论
5个回答

4
你可以忽略Modified UTF-8 Encoding (MUTF-8),并将其视为UTF-8。在Python端,你只需要像这样处理它:
  1. 将字符串转换为普通的UTF-8,并将字节存储在缓冲区中。
  2. 以大端二进制形式写入2字节缓冲区长度(而不是字符串长度)。
  3. 写入整个缓冲区。
我已经在PHP中完成了这个操作,在Java 5中也没有出现任何关于我的编码的问题。
MUTF-8主要用于JNI和其他使用空终止字符串的系统。与普通的UTF-8唯一的区别在于U+0000的编码方式。普通的UTF-8使用1字节编码(0x00),而MUTF-8则使用2字节编码(0xC0 0x80)。首先,你不应该在任何Unicode文本中使用无效代码点U+0000。其次,DataInputStream.readUTF()不强制执行编码,因此它可以接受任何一个编码。
编辑:Python代码应该如下所示:
def writeUTF(data, str):
    utf8 = str.encode('utf-8')
    length = len(utf8)
    data.append(struct.pack('!H', length))
    format = '!' + str(length) + 's'
    data.append(struct.pack(format, utf8))

4
U+0000并不是唯一的区别。对于在UTF-16中需要用代理对表示的代码点,修改后的UTF-8编码将每个代理对组成部分都编码为单独的UTF-8代码点。这很糟糕,因为这意味着你必须先从"修改后的UTF-8"转换为UTF-16,然后再转回来才能正确编码代码点。 - Cogwheel
1
我认为你不能忽略它:UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc0 in position 10: invalid start byte - Chris Stryczynski

3

我知道这个问题非常古老,但我仍然想做出贡献,因为我遇到了同样的问题并解决了它。

我在openjdk源代码中找到了这个修改后的utf8的实现,并将其翻译成了Python。这里是我创建的链接


1

好的,如果您需要阅读 DataInput.readUTF 的格式,我猜想你可能需要将(有良好文档记录的)格式转换成Python。

这似乎并不特别难。在读取长度和二进制数据本身后,建议您先进行第一遍处理,以确定输出中将有多少Unicode字符,然后在第二遍处理中相应地构造字符串。我并不了解Python的内部工作机制,但根据相关规范,我想象它不会很难。您可以查看现有的UTF-8解码器源代码作为起点。


1

有一个Python包可以处理MUTF-8字符串的读写,还带有可选的C扩展:https://github.com/TkTech/mutf8

from mutf8 import encode_modified_utf8, decode_modified_utf8

unicode = decode_modified_utf8(byte_like_object)
bytes = encode_modified_utf8(unicode)

0
也许这可以帮助你,尽管它看起来与你所做的相反:
连接Java小程序到Python SocketServer

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