【问题标题】:Emoji reading discrepancy between different applications不同应用程序之间的表情符号阅读差异
【发布时间】:2021-05-15 16:01:54
【问题描述】:

我有一堆需要处理的推文/线程数据集,以及一些单独的注释文件。这些注释文件由一些跨度组成,这些跨度由对应于单词/句子的索引表示。正如您可能已经预测的那样,索引是推文/线程文件中字符的位置。

当我处理带有一些表情符号的文件时,问题就出现了。举一个具体的例子:

这是相关文件的一部分 (download):

TeamKhabib  ???????????? @danawhite @seanshelby @arielhelwani @AliAbdelaziz00 #McTapper xxxxx://x.xx/xxxxxxxxxx
mmafan1709  @TeamKhabib @danawhite @seanshelby @arielhelwani @AliAbdelaziz00 Conor is Khabib hardest fight and Khabib is Conors hardest fight

我在 python 中使用普通打开函数读取文件,参数 encoding='utf8':

with open('028_948124816611139589.branch318.txt.username_text_tabseparated', 'r', encoding='utf-8') as f:
    content = f.read()
    print(content[211:214])

注释说在 211-214 范围内有单词 and。我上面提到的阅读方式,有'kh'

当我使用注释文件中的索引来获取跨越的字符串时,我得到的字符串是 3 个字符(右侧)。因为,在注释中,????显然需要 2 个空格。但是,当 python 读取它们时,它是一个,因此字符移位。当我用len(list(file.read())) 获得文件的长度时,它变得更加明显。这将返回 7809,而文件的实际长度是 7812。7812 是我在 vscode 中的文件末尾得到的位置,一个名为 vscode-position 的插件。另一个文件给我的 513 和 527 不一致。

阅读表情符号没有问题,我在输出/数组中看到它们,但是它们在编码中占用的空间不同。我的问题在其他相关问题中没有得到解答。

很明显,阅读这个文件是有道理的,因为这些文件是用某种格式/方法/概念/编码/无论这个插件和注释者同意的,但 open.read 不同意的。

我正在使用 python 3.8。

我在这里错过了什么?

【问题讨论】:

  • 文本保存为 Unicode 代码点到字节的编码。 ???是单个代码点,但在 UTF-8 编码中编码为 3 个字节。 Python中Unicode字符串的长度是codepoints,文件的长度是bytes,所以会有区别。如果您的注释文件是字节索引,您可能需要将文件读取为二进制文件 ('rb'),然后手动解码。
  • @MarkTolonen 嗯。正如您所说,我认为 7812 是字节偏移量,而 7809 是代码点。但是用 'rb' 读取它们然后应用 decode('utf8') 并没有任何区别。
  • 不,读取二进制文件,获取特定偏移量的字节,然后解码。如果您需要解决方案,请发布带有适当注释和代码的真实示例文本,以显示您的问题。
  • @MarkTolonen 也没有用。假设它是字节偏移量,我错了,实际上文件是 7856 字节。通过这样做,我在左边得到了 6 个字符。并将文件添加到问题中。
  • 如果没有附带的注释,它就真的没用了。我将发布一个我正在谈论的示例作为答案。

标签: python encoding utf-8 emoji


【解决方案1】:

我相信在讨论后这个问题是跨度是从使用代理对的 Unicode 字符串计算的 Unicode 代码点 > U+FFFF。 Python 2 和 Java 和 C# 等其他语言使用 UTF-16 代码单元而不是 Python 3 等抽象代码点存储 Unicode 字符串。如果我将测试数据视为 UTF-16LE 编码,答案就出来了:

import re

# Important to note that the original file has two tabs in it that SO doesn't display.
#  * Between the first "TeamKabib" and smiley
#  * Between "mmafan1709" and "@TeamKhabib"
# Use the download link while it is valid.

with open('test.txt', 'r', encoding='utf-8') as f:
    content = f.read()
    b = content.encode('utf-16le')
    print(b[211 * 2:214 * 2].decode('utf-16le'))

# result: and

因为每个 UTF-16 编码单元是两个字节,所以偏移量需要加倍,所以必须对结果进行解码才能正确显示。

我专门使用了utf-16leutf-16,因为后者会添加一个 BOM 并抛出另外两个字节(或一个代码单元)的计数。


【讨论】:

  • 这似乎很好用!感谢您的宝贵时间!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
相关资源
最近更新 更多