Skip to content

line_indexer

zocrates.rag.line_indexer

Precomputed character-offset indexing utilities for line mapping.

Provides fast, deterministic, 1-indexed line number resolution for converted Markdown documents, shared across ToC generation and chunking pipelines.

LineIndex

LineIndex(text)

Precomputed character-offset index for fast, deterministic character-to-line mapping.

Construct a line index from source text.

Parameters:

Name Type Description Default
text str

Raw input text.

required
Source code in zocrates/rag/line_indexer.py
def __init__(self, text: str) -> None:
    """Construct a line index from source text.

    Args:
        text: Raw input text.
    """
    lines = text.splitlines(keepends=True)
    if not lines:
        lines = [""]
    self.total_lines = len(lines)
    self.offsets: list[int] = [0]
    for line in lines[:-1]:
        self.offsets.append(self.offsets[-1] + len(line))

char_to_line

char_to_line(char_pos)

Map a 0-indexed character position to a 1-indexed line number.

Parameters:

Name Type Description Default
char_pos int

Character position in source text.

required

Returns:

Type Description
int

1-indexed line number clamped to [1, total_lines].

Source code in zocrates/rag/line_indexer.py
def char_to_line(self, char_pos: int) -> int:
    """Map a 0-indexed character position to a 1-indexed line number.

    Args:
        char_pos: Character position in source text.

    Returns:
        1-indexed line number clamped to ``[1, total_lines]``.
    """
    idx = bisect.bisect_right(self.offsets, char_pos) - 1
    return max(1, min(self.total_lines, idx + 1))

span_to_lines

span_to_lines(start_char, end_char)

Map a half-open character range [start_char, end_char) to 1-indexed line bounds.

Parameters:

Name Type Description Default
start_char int

0-indexed inclusive start character position.

required
end_char int

0-indexed exclusive end character position.

required

Returns:

Type Description
tuple[int, int]

Tuple of (line_start, line_end) where line_start <= line_end.

Source code in zocrates/rag/line_indexer.py
def span_to_lines(self, start_char: int, end_char: int) -> tuple[int, int]:
    """Map a half-open character range ``[start_char, end_char)`` to 1-indexed line bounds.

    Args:
        start_char: 0-indexed inclusive start character position.
        end_char: 0-indexed exclusive end character position.

    Returns:
        Tuple of ``(line_start, line_end)`` where ``line_start <= line_end``.
    """
    if start_char > end_char:
        start_char, end_char = end_char, start_char
    l_start = self.char_to_line(start_char)
    l_end = self.char_to_line(max(start_char, end_char - 1))
    return l_start, max(l_start, l_end)

char_offset_to_line

char_offset_to_line(offsets, char_pos, total_lines=None)

Binary search character offset to 1-indexed line number.

Parameters:

Name Type Description Default
offsets list[int]

List of character start offsets for each line (0-indexed).

required
char_pos int

Character index in document.

required
total_lines int | None

Optional total number of lines to clamp the maximum line number.

None

Returns:

Type Description
int

1-indexed line number.

Source code in zocrates/rag/line_indexer.py
def char_offset_to_line(
    offsets: list[int],
    char_pos: int,
    total_lines: int | None = None,
) -> int:
    """Binary search character offset to 1-indexed line number.

    Args:
        offsets: List of character start offsets for each line (0-indexed).
        char_pos: Character index in document.
        total_lines: Optional total number of lines to clamp the maximum line number.

    Returns:
        1-indexed line number.
    """
    idx = bisect.bisect_right(offsets, char_pos) - 1
    res = max(1, idx + 1)
    if total_lines is not None:
        res = min(total_lines, res)
    return res