class EL_ITERABLE_SPLIT_CURSOR
Cursor for target string sections split by separator of type SEP
note
description: "Cursor for `target' string sections split by separator of type **SEP**"
author: "Finnian Reilly"
copyright: "Copyright (c) 2001-2022 Finnian Reilly"
contact: "finnian at eiffel hyphen loop dot com"
license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
date: "2025-04-17 12:45:28 GMT (Thursday 17th April 2025)"
revision: "17"
deferred class
EL_ITERABLE_SPLIT_CURSOR [RSTRING -> READABLE_STRING_GENERAL, CHAR -> COMPARABLE, SEPARATOR]
inherit
ITERATION_CURSOR [RSTRING]
rename
item as item_copy
end
EL_ITERABLE_SPLIT_BASE [RSTRING, SEPARATOR]
EL_LIST_ITEM_SUBSTRING_CONVERSION
feature {NONE} -- Initialization
initialize
do
if not target.is_immutable and then attached {STRING_GENERAL} target as general then
internal_item := general.substring (1, 0)
end
forth
end
feature -- Access
cursor_index: INTEGER
item: like target
-- dynamic singular substring of `target' at current split position if the
-- `target' conforms to `STRING_GENERAL' else the value of `item_copy'
-- use `item_copy' if you intend to keep a reference to `item' beyond the scope of the
-- client routine
do
if attached internal_item as l_item then
fill_item (l_item)
if attached {like target} l_item as substring_item then
Result := substring_item
else
Result := item_copy
end
else
Result := item_copy
end
end
item_copy: like target
-- new substring of `target' at current split position
do
Result := target.substring (item_lower, item_upper)
end
item_count: INTEGER
do
Result := item_upper - item_lower + 1
end
item_index_of (c: CHAR; start_index: INTEGER): INTEGER
local
i: INTEGER
do
if attached target as l_target and then start_index <= item_count then
from i := item_lower + start_index - 1 until i > item_upper or else Result > 0 loop
if i_th_character (l_target, i) = c then
Result := i - item_lower + 1
end
i := i + 1
end
end
end
item_lower: INTEGER
-- start index of `item' in `target' string
item_upper: INTEGER
-- end index of `item' in `target' string
feature -- Optimized operations
append_item_to (general: STRING_GENERAL)
-- equivalent to appending `item' to `general'
do
general.append_substring (target, item_lower, item_upper)
end
fill_with_item (general: STRING_GENERAL)
-- equivalent to `general.replace_substring (1, general.count, item)' even
-- though routine `replace_substring' on exists in descendants
do
general.keep_head (0)
general.append_substring (target, item_lower, item_upper)
end
sink_item_to (sink: EL_DATA_SINKABLE)
do
end
feature -- Status query
after: BOOLEAN
-- Are there no more items to iterate over?
is_last: BOOLEAN
-- `True' if cursor is currently on the last `item'
item_has (c: CHAR): BOOLEAN
local
i: INTEGER
do
if attached target as l_target then
from i := item_lower until i > item_upper or else Result loop
Result := i_th_character (l_target, i) = c
i := i + 1
end
end
end
item_is_empty: BOOLEAN
do
Result := item_upper < item_lower
end
item_same_as (str: like target): BOOLEAN
do
if item_upper - item_lower + 1 = str.count then
if str.count = 0 then
Result := item_upper + 1 = item_lower
else
Result := same_characters (target, str, 1, str.count, item_lower)
end
end
end
item_same_caseless_as (str: like target): BOOLEAN
do
if item_upper - item_lower + 1 = str.count then
if str.count = 0 then
Result := item_upper + 1 = item_lower
else
Result := same_caseless_characters (target, str, 1, str.count, item_lower)
end
end
end
item_starts_with (str: like target): BOOLEAN
do
if str.count = 0 then
Result := True
elseif item_upper - item_lower + 1 >= str.count then
Result := same_characters (target, str, 1, str.count, item_lower)
end
end
feature -- Cursor movement
forth
-- Move cursor to next position.
local
previous_separator_end: INTEGER; found_first: BOOLEAN
do
if is_last then
after := True
else
previous_separator_end := separator_end
set_separator_start
if separator_start > 0 then
separator_end := separator_start + separator_count - 1
item_lower := previous_separator_end + 1
item_upper := separator_start - 1
else
item_lower := separator_end + 1
item_upper := target.count
is_last := True
end
if left_adjusted and then attached target as l_target then
from until found_first or else item_lower > item_upper loop
if is_i_th_white_space (l_target, item_lower) then
item_lower := item_lower + 1
else
found_first := True
end
end
end
if right_adjusted and then attached target as l_target then
found_first := False
from until found_first or else item_upper < item_lower loop
if is_i_th_white_space (l_target, item_upper) then
item_upper := item_upper - 1
else
found_first := True
end
end
end
cursor_index := cursor_index + 1
end
end
feature {EL_ITERABLE_SPLIT} -- Implementation
fill_item (a_item: STRING_GENERAL)
do
end
i_th_character (a_target: like target; i: INTEGER): CHAR
-- i'th character of `a_target'
deferred
end
is_i_th_white_space (a_target: like target; i: INTEGER): BOOLEAN
-- `True' if i'th character of `a_target' is white space
deferred
end
same_caseless_characters (a_target, other: like target; start_pos, end_pos, index_pos: INTEGER): BOOLEAN
-- Are characters of `other' within bounds `start_pos' and `end_pos'
-- caseless identical to characters of current string starting at index `index_pos'.
do
Result := a_target.same_caseless_characters (other, start_pos, end_pos, index_pos)
end
same_characters (a_target, other: like target; start_pos, end_pos, index_pos: INTEGER): BOOLEAN
-- Are characters of `other' within bounds `start_pos' and `end_pos'
-- identical to characters of current string starting at index `index_pos'.
do
Result := a_target.same_characters (other, start_pos, end_pos, index_pos)
end
set_separator_start
deferred
end
feature {NONE} -- Internal attributes
internal_item: detachable STRING_GENERAL
separator_end: INTEGER
-- end index of separator
separator_start: INTEGER
-- start index of separator
end