character_range.ranges#

The highest-level features of the package, implemented as _Range, StringRange and BytesRange.

class StringRange(start: _StrOrBytes, end: _StrOrBytes, /, index_map: IndexMap[_StrOrBytes])[source]#

Bases: _Range[str]

class BytesRange(start: _StrOrBytes, end: _StrOrBytes, /, index_map: IndexMap[_StrOrBytes])[source]#

Bases: _Range[bytes]

class _Range(start: _StrOrBytes, end: _StrOrBytes, /, index_map: IndexMap[_StrOrBytes])[source]#

Bases: Generic[_StrOrBytes], ABC

Represents a range between two string or bytes object endpoints.

A range of this type is always a closed interval: both endpoints are inclusive. This goes in line with how regex character ranges work, even though those only ever support single characters:

>>> list(StringRange('a', 'c', CharacterMap.ASCII_LOWERCASE))
['a', 'b', 'c']
>>> list(StringRange('aa', 'ac', CharacterMap.ASCII_LOWERCASE))
['aa', 'ab', 'ac']

For BytesRange, each byte of the yielded bytes objects will have the corresponding integral values ranging from 0 through 0xFF:

>>> list(BytesRange(b'0xFE', b'0x81', ByteMap.ASCII))
[b'0xFE', b'0xFF', b'0x80', b'0x81']

Also note that the next value after [base - 1] is [0, 0], not [1, 0]:

>>> list(StringRange('0', '19', CharacterMap.ASCII_DIGITS))
[
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
  '00', '01', '02', '03', '04', '05', '06', '07', '08', '09',
  '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'
]

See also _IncrementableIndexCollection.

Magic methods

__iter__() Iterator[_StrOrBytes][source]#

Lazily yield the elements.

__len__() int[source]#

The number of elements the range would yield, calculated mathematically.

Properties

property start: _StrOrBytes#

The starting endpoint of the range.

property end: _StrOrBytes#

The ending endpoint of the range.

property map: IndexMap[_StrOrBytes]#

The map to look up the available characters or bytes.

property element_type: type[_StrOrBytes]#

The element type of map().

See IndexMap.element_type().

class _IncrementableIndexCollection(indices: Iterable[int], /, base: int)[source]#

Bases: object

A collection of indices of a IndexMap that can be incremented one by one.

_MonotonicIndexCollection.increment() works in an index-wise manner:

>>> c = _IncrementableIndexCollection([1], 2)
>>> c.increment()
_IncrementableIndexCollection([0, 0], base = 2)

Magic methods

__index__() int[source]#

The integeral value computed by interpreting the indices as the digits of a base-n integer.

__len__() int[source]#

The number of indices the collection currently holds.

__iter__() Iterator[int][source]#

Lazily yield the elements this collection currently holds.

__lt__(other: Self) bool[source]#

Whether other’s length is greater than self’s or the lengths are equals but the integral value of other is greater than that of self.

__eq__(other: object) bool[source]#

Whether two collections have the same base and elements.

Properties

property base: int#

The maximum value of an index, plus 1.

Methods

increment() Self[source]#

Add 1 to the last index. If the new value is equals to base, that index will become 0 and the process continues at the next index. If the last index is reached, a new index (0) is added to the list.

This is equivalent to C/C++’s pre-increment operator, in that it returns the original value after modification.

Examples:

[0, 0] -> [0, 1]
[0, 1] -> [1, 0]
[1, 1] -> [0, 0, 0]
exception InvalidEndpoints(*endpoints: str | bytes)[source]#

Bases: ValueError

Raised when the endpoints given to _Range is either:

  • Empty, or

  • At least one character is not in the corresponding map.

exception InvalidRangeDirection(start: object, end: object)[source]#

Bases: ValueError

Raised when start is longer than end or they have the same length but start is lexicographically “less than” end.