将字符偏移转换为字节偏移(在Python中)
假设我有一堆UTF-8编码的文件,我把它们发送到一个外部的API,这个API处理每个unicode字符串,并返回一个包含(字符偏移量, 子字符串)
的列表。
我需要的输出是每个找到的子字符串的起始和结束字节偏移量。如果运气好,输入的文本只包含ASCII字符(这样字符偏移量和字节偏移量是一样的),但这并不总是如此。我该如何根据已知的起始字符偏移量和子字符串来找到起始和结束的字节偏移量呢?
我自己已经回答了这个问题,但我期待看到其他更健壮、更高效和/或更易读的解决方案。
2 个回答
1
当需要把字符位置转换成字节位置时,如果输入的文本中有非ASCII字符,我会先用 encode('utf8')
方法把找到的子字符串之前的文本进行编码,然后把编码后的长度作为起始位置。
# Check if text contains non-ASCII characters
needs_offset_conversion = len(text) != len(text.encode('utf8'))
def get_byte_offsets(text, character_offset, substr, needs_conversion):
if needs_conversion:
begin_offset = len(text[:character_offset].encode('utf8'))
end_offset = begin_offset + len(substr.encode('utf8'))
else:
begin_offset = character_offset
end_offset = character_offset + len(substr)
return begin_offset, end_offset
这个方法是可行的,但每次找到子字符串时都要对一大段文本进行编码,效率不是很高。
5
我会用一个字典来解决这个问题,这个字典可以把字符的位置映射到字节的位置,然后再根据这个字典来查找位置。
def get_char_to_byte_map(unicode_string):
"""
Generates a dictionary mapping character offsets to byte offsets for unicode_string.
"""
response = {}
byte_offset = 0
for char_offset, character in enumerate(unicode_string):
response[char_offset] = byte_offset
byte_offset += len(character.encode('utf-8'))
return response
char_to_byte_map = get_char_to_byte_map(text)
for begin_offset, substring in api_response:
begin_offset = char_to_byte_map[character_offset]
end_offset = char_to_byte_map[character_offset + len(substring)]
# do something
这个方法的性能和你的方法相比,主要取决于输入的大小和涉及的子字符串的数量。通过一些小规模的测试发现,单独编码每一个字符的时间大约是一次性编码整个文本的1000倍。