在UTF8 fi中逐个字符

2024-10-01 09:39:37 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个ASCII文件(叫做'测试.txt')像这样:

A B C D
X Y Z
     ^   EOF, no CR after the 'Z'...

在Python中,我可以像这样读取最后一个字节(最后一个字符):

^{pr2}$

我可以这样截短最后3个字符:

with open('test.txt', 'r') as f:
    f.seek(-3, os.SEEK_END)
    f.truncate()

现在假设我有第二个文件(名为'测试.utf')用UTF-8编码,具有以下单字节和多字节字符:

A B C D
Ⓐ Ⓑ Ⓒ Ⓓ
Z Ⓩ

我知道如何读取整个文件(使用编解码器):

>>> f=codecs.open('/tmp/test.utf', 'r', 'utf-8')
>>> L=f.readlines()
>>> L
[u'A B C D\n', u'\u24b6 \u24b7 \u24b8 \u24b9\n', u'Z \u24cf']

我想我可以使用collections模块中的deque来获取最后N个字符:

>>> from collections import deque
>>> with codecs.open(fn,'r+', encoding) as f:
...    last_3=deque(f.read(),3)
>>> last_3
deque([u'Z', u' ', u'\u24cf'], maxlen=3)

那么,问题是:有没有什么地方可以让我在逻辑上一个字符一个接一个地从UTF-8文件中退一步,而不用把整个文件读入内存中?使用ASCII很容易;只需在文件开头附近查找一个字节。但是在UTF-8中,是3个字节(E2 93 8F),而{}只是一个字节。在

回想一下,UTF-8的宽度是可变的——每个字符在1到4个字节之间。除非你从一开始就开始,否则我认为没有办法知道角色的界限是什么。。。在


Tags: 文件testtxt字节aswithasciiopen
2条回答

Unless you start at the beginning, I am think there is no way to know what the character boundaries are...

那不是真的。你可以在UTF-8的任何一块中找到开头:

  • 如果给定字节中的第一位被设置,则它是多字节序列的一部分。在
  • 如果第二位也被设置,它就是这样一个序列的开始。在

所以序列中的第一个字节要么以“0”(单字节字符)或“11”(两个或多个字节的第一个)开头。后续字节都以“10”开头。在

看看这个chart on Wikipedia。在

因此,您只需从文件末尾读取几个字节即可确定字符的开始和结束位置。在

你可以这样做,但不能作为个人角色。将文件视为字节。在

每个UTF-8字符由1到4个字节组成。要读取文件的结尾,请读取最后4*n个字节并开始查找字符边界。UTF-8字符的第一个字节具有011的顶层模式,中间的所有其他字节都将采用10模式。只需向后搜索,直到计算出与图案匹配的正确数字。在

with open('test.txt', 'rb') as f:
    f.seek(-4, os.SEEK_END)
    ch=f.read(4)
    for i in range(3, -1, -1):
        pattern = ord(ch[i]) & 0xc0
        if pattern in (0x00, 0x40, 0xc0):
            ch = ch[i:]
            break

相关问题 更多 >