class Line: def __init__(self, byte_offset: int, byte_end: int, line: str): self._byte_offset = byte_offset self._byte_end = byte_end self._line = line def byte_offset(self) -> int: return self._byte_offset def byte_end(self) -> int: return self._byte_end def line(self) -> str: return self._line def length(self) -> int: return len(self._line) def char_index_to_byte(self, char_in_line: int) -> int: return len(self.prefix(char_in_line).encode("utf8")) def byte_index_to_char_index(self, byte_index: int) -> int: prefix_bytes = self._line.encode("utf8")[:byte_index] prefix_chars = prefix_bytes.decode("utf8", errors="ignore") return len(prefix_chars) def includes_byte(self, byte: int) -> bool: return self._byte_offset <= byte <= self._byte_end def intersects(self, start_byte: int, end_byte: int): result = start_byte < self._byte_end and end_byte > self._byte_offset #print("%d,%d in %d,%d" % (start_byte, end_byte, self._byte_offset, self._byte_end)) return result def prefix(self, index: int) -> str: return self._line[0:index] def substr(self, offset: int, length: int) -> str: return self._line[offset:offset+length] def suffix(self, index: int) -> str: return self._line[index:] def __str__(self): return "%s (%d->%d)" % (self._line, self._byte_offset, self._byte_end)