Commit 52102eea authored by Eckhart Arnold's avatar Eckhart Arnold
Browse files

- class StringSlice added to syntax tree

parent 7895ea53
......@@ -43,7 +43,7 @@ except ImportError:
import DHParser.shadow_cython as cython
__all__ = ('StringView', 'slow_real_indices', 'EMPTY_STRING_VIEW')
__all__ = ('StringView', 'real_indices', 'EMPTY_STRING_VIEW')
@cython.cfunc
......@@ -95,9 +95,9 @@ def pack_index(index: int, length: int) -> int:
@cython.cfunc
@cython.returns((cython.int, cython.int))
@cython.locals(cbegin=cython.int, cend=cython.int, length=cython.int)
def real_indices(begin: Optional[int],
end: Optional[int],
length: int) -> Tuple[int, int]:
def fast_real_indices(begin: Optional[int],
end: Optional[int],
length: int) -> Tuple[int, int]:
"""Returns the tuple of real (i.e. positive) indices from the slice
indices `begin`, `end`, assuming a string of size `length`.
"""
......@@ -106,11 +106,11 @@ def real_indices(begin: Optional[int],
return pack_index(cbegin, length), pack_index(cend, length)
def slow_real_indices(begin: Optional[int],
end: Optional[int],
length: int) -> Tuple[int, int]:
def real_indices(begin: Optional[int],
end: Optional[int],
length: int) -> Tuple[int, int]:
"""Python callable real-indices function for testing."""
return real_indices(begin, end, length)
return fast_real_indices(begin, end, length)
class StringView: # collections.abc.Sized
......@@ -126,7 +126,7 @@ class StringView: # collections.abc.Sized
def __init__(self, text: str, begin: Optional[int] = 0, end: Optional[int] = None) -> None:
# assert isinstance(text, str)
self._text = text # type: str
self._begin, self._end = real_indices(begin, end, len(text))
self._begin, self._end = fast_real_indices(begin, end, len(text))
self._len = self._end - self._begin # type: int
if self._len < 0:
self._len = 0
......@@ -181,7 +181,7 @@ class StringView: # collections.abc.Sized
# assert index.step is None or index.step == 1, \
# "Step sizes other than 1 are not yet supported by StringView"
try:
start, stop = real_indices(index.start, index.stop, self._len)
start, stop = fast_real_indices(index.start, index.stop, self._len)
return StringView(self._text, self._begin + start, self._begin + stop)
except AttributeError:
return StringView(self._text, self._begin + index, self._begin + index + 1)
......@@ -205,7 +205,7 @@ class StringView: # collections.abc.Sized
elif start is None and end is None:
return self._text.count(sub, self._begin, self._end)
else:
_start, _end = real_indices(start, end, self._len)
_start, _end = fast_real_indices(start, end, self._len)
return self._text.count(sub, self._begin + _start, self._begin + _end)
@cython.locals(_start=cython.int, _end=cython.int)
......@@ -223,7 +223,7 @@ class StringView: # collections.abc.Sized
elif start is None and end is None:
return max(self._text.find(sub, self._begin, self._end) - self._begin, -1)
else:
_start, _end = real_indices(start, end, self._len)
_start, _end = fast_real_indices(start, end, self._len)
return max(self._text.find(sub, self._begin + _start, self._begin + _end)
- self._begin, -1)
......@@ -242,7 +242,7 @@ class StringView: # collections.abc.Sized
if start is None and end is None:
return max(self._text.rfind(sub, self._begin, self._end) - self._begin, -1)
else:
_start, _end = real_indices(start, end, self._len)
_start, _end = fast_real_indices(start, end, self._len)
return max(self._text.rfind(sub, self._begin + _start, self._begin + _end)
- self._begin, -1)
......
......@@ -33,7 +33,7 @@ from typing import Callable, cast, Iterator, Sequence, List, AbstractSet, Set, U
from DHParser.configuration import SERIALIZATIONS, XML_SERIALIZATION, SXPRESSION_SERIALIZATION, \
COMPACT_SERIALIZATION, JSON_SERIALIZATION, SMART_SERIALIZATION, get_config_value
from DHParser.error import Error, ErrorCode, linebreaks, line_col
from DHParser.stringview import StringView
from DHParser.stringview import StringView, real_indices
from DHParser.toolkit import re, cython
......@@ -1446,6 +1446,44 @@ class DHParser_JSONEncoder(json.JSONEncoder):
return json.JSONEncoder.default(self, obj)
#######################################################################
#
# string slices of a tree
#
#######################################################################
class StringSlice:
def __init__(self, tree: Node):
self.tree = tree # type: Node
@cython.locals(start=cython.int, stop=cython.int, delta=cython.int, l=cython.int, i=cython.int)
def __getitem__(self, index: Union[slice, int]) -> str:
try:
start, stop = real_indices(index.start, index.stop, self._len)
l = 0
str_list = []
for leaf in self.tree.select_if(lambda nd: bool(not nd.children)):
delta = len(leaf)
if l <= start < l + delta:
str_list.append(leaf.result[start - l:stop - l])
elif l < stop:
str_list.append(leaf.result[:stop - l])
if stop <= l + delta:
return ''.join(str_list)
l += delta
except AttributeError:
# index is an integer value
i = index
l = 0
for leaf in self.tree.select_if(lambda nd: bool(not nd.children)):
delta = len(leaf)
if l <= i < l + delta:
return leaf.result[i-l]
l += delta
#######################################################################
#
# S-expression- and XML-parsers and JSON-reader
......
......@@ -26,19 +26,19 @@ scriptpath = os.path.dirname(__file__) or '.'
sys.path.append(os.path.abspath(os.path.join(scriptpath, '..')))
from DHParser.toolkit import re
from DHParser.stringview import StringView, EMPTY_STRING_VIEW, slow_real_indices
from DHParser.stringview import StringView, EMPTY_STRING_VIEW, real_indices
class TestStringView:
def test_slow_real_indices(self):
assert slow_real_indices(3, 5, 10) == (3, 5)
assert slow_real_indices(None, None, 10) == (0, 10)
assert slow_real_indices(-2, -1, 10) == (8, 9)
assert slow_real_indices(-3, 11, 10) == (7, 10)
assert slow_real_indices(-5, -12, 10) == (5, 0)
assert slow_real_indices(-12, -5, 10) == (0, 5)
assert slow_real_indices(7, 6, 10) == (7, 6)
assert slow_real_indices(None, 0, 10) == (0, 0)
assert real_indices(3, 5, 10) == (3, 5)
assert real_indices(None, None, 10) == (0, 10)
assert real_indices(-2, -1, 10) == (8, 9)
assert real_indices(-3, 11, 10) == (7, 10)
assert real_indices(-5, -12, 10) == (5, 0)
assert real_indices(-12, -5, 10) == (0, 5)
assert real_indices(7, 6, 10) == (7, 6)
assert real_indices(None, 0, 10) == (0, 0)
def test_creation(self):
s = "0123456789"
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment