java - 在 Python 中使用 Unicode 保持 Java 字符串偏移量一致

标签 java python string unicode

我们正在构建一个调用 Java 程序的 Python 3 程序。 Java 程序(这是我们无法修改的第 3 方程序)用于标记字符串(查找单词)并提供其他注释。这些注释采用字符偏移量的形式。

例如,我们可能会为程序提供字符串数据,例如“lovely weather today”。它提供类似于以下输出的内容:

0,6
7,14
15,20

其中0,6是单词“lovely”对应的偏移量,7,14是单词“weather”和15对应的偏移量, 20 是源字符串中与单词“today”相对应的偏移量。我们在 Python 中读取这些偏移量以提取这些点的文本并执行进一步处理。

只要字符在基本多语言平面 (BMP) 内,一切都很好。然而,如果它们不是,则此 Java 程序报告的偏移量在 Python 端显示完全错误。

例如,给定字符串 "I feel 🙂 today",Java 程序将输出:

0,1
2,6
7,9
10,15

在 Python 方面,这些转换为:

0,1    "I"
2,6    "feel"
7,9    "🙂 "
10,15  "oday"

最后一个索引在技术上是无效的。 Java 将“🙂”视为长度 2,从 Python 程序的角度来看,这会导致该点之后的所有注释都减一。

大概是因为 Java 在内部以 UTF-16esqe 方式对字符串进行编码,并且所有字符串操作都作用于那些 UTF-16esque code units .另一方面,Python 字符串似乎对实际的 unicode 字符(代码点)进行操作。因此,当字符出现在 BMP 之外时,Java 程序将其视为长度 2,而 Python 将其视为长度 1。

所以现在的问题是:在 Python 使用它们之前“纠正”这些偏移量的最佳方法是什么,以便注释子字符串与 Java 程序打算输出的内容一致?

最佳答案

您可以将字符串转换为 UTF16 编码的字节数组,然后使用偏移量(乘以 2,因为每个 UTF-16 代码单元有两个字节)来索引该数组:

x = "I feel 🙂 today"
y = bytearray(x, "UTF-16LE")

offsets = [(0,1),(2,6),(7,9),(10,15)]

for word in offsets:
  print(str(y[word[0]*2:word[1]*2], 'UTF-16LE'))

输出:

I
feel
🙂
today

或者,您可以将字符串中的每个 Python 字符单独转换为 UTF-16 并计算它需要的代码单元数。这使您可以将根据代码单元(来自 Java)的索引映射到根据 Python 字符的索引:

from itertools import accumulate

x = "I feel 🙂 today"
utf16offsets = [(0,1),(2,6),(7,9),(10,15)] # from java program

# map python string indices to an index in terms of utf-16 code units
chrLengths = [len(bytearray(ch, "UTF-16LE"))//2 for ch in x]
utf16indices = [0] + list(itertools.accumulate(chrLengths))
# reverse the map so that it maps utf16 indices to python indices
index_map = dict((x,i) for i, x in enumerate(utf16indices))

# convert the offsets from utf16 code-unit indices to python string indices
offsets = [(index_map[o[0]], index_map[o[1]]) for o in utf16offsets]

# now you can just use those indices as normal
for word in offsets:
  print(x[word[0]:word[1]])

输出:

I
feel
🙂
today

上面的代码很乱,可能可以更清楚一些,但你明白了。

关于java - 在 Python 中使用 Unicode 保持 Java 字符串偏移量一致,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56280011/

相关文章:

java - 如何检查一个 ParameterizedType 是否代表另一个 ParameterizedType 的子类型?

java - 如何使用 MongoTemplate 将单个字段插入到 JSON 中?

python - 打包 Django 项目的推荐方式?具有多个应用程序或多个 Django 包的 Django 包?

php - 在php中将二进制字符串转换为整数

php - MySQL 十进制字段在 PHP 中作为字符串返回

Java:接口(interface)和返回接口(interface)的函数的实现

java - jdbcTemplate 的 setMaxRows 如何工作

python - Scrapy在什么情况下会抛出 "Connection was closed cleanly"错误?

python - docker crontab : not found

c - 在 C 中定义和打印字符串变量的正确格式是什么?