note description: "Comparator for character sets" legal: "See notice at end of class." status: "See notice at end of class." date: "$Date$" revision: "$Revision$" usage: "The features 'define', 'add' and 'remove' accept a string as% %argument that represents a set of single character (like 'a')% %or character ranges (like 'a-z'). To use a character with a% %special meaning (like '-') as single character, it can be quoted% %using the character '\'" class CHARACTER_SET inherit TO_SPECIAL [BOOLEAN] redefine default_create end feature {NONE} -- Initialization default_create -- Initialize `Current'. do make_filled_area (False, {CHARACTER}.Max_value + 1) end feature -- Access contains_string (s: STRING): BOOLEAN -- Does character set contain string `s'? require not_empty: not is_empty string_exists: s /= Void local i, cnt: INTEGER str: SPECIAL [CHARACTER] do from str := s.area cnt := s.count Result := True until i = cnt or not Result loop Result := area.item (str.item (i).code) i := i + 1 end end contains_character (c: CHARACTER): BOOLEAN -- Does character set contain character `c'? require not_empty: not is_empty do Result := area.item (c.code) end feature -- Status report is_empty: BOOLEAN -- Is character set empty? local i, cnt: INTEGER do from cnt := area.count until i = cnt or Result loop Result := area.item (i) i := i + 1 end Result := not Result end feature -- Status setting define (s: STRING) -- Define character set. require string_exists: s /= Void not_open_set: (s.item (1) /= '-') and (s.item (s.count) /= '-') local i, cnt: INTEGER do -- First reinitialize the set to an empty set. from cnt := area.count until i = cnt loop area.put (False, i) i := i + 1 end if not s.is_empty then process_string (s, True) end end feature -- Element change add (s: STRING) -- Add `s' to character set. require non_empty_string: s /= Void and then not s.is_empty not_open_set: (s.item (1) /= '-') and (s.item (s.count) /= '-') do process_string (s, True) end feature -- Removal remove (s: STRING) -- Remove `s' from character set. require non_empty_string: s /= Void and then not s.is_empty not_open_set: (s.item (1) /= '-') and (s.item (s.count) /= '-') do process_string (s, False) end feature {NONE} -- Implementation process_string (s: STRING; for_addition: BOOLEAN) -- Add or remove (depending on `for_addition') the characters that `s' defines to/from the set. require valid_string: s /= Void and not s.is_empty not_open_set: (s.item (1) /= '-') and (s.item (s.count) /= '-') local escape: BOOLEAN lastc, curc: CHARACTER i, cnt: INTEGER do from i := 1 lastc := s.item (i) escape := lastc = '\' cnt := s.count until i = cnt loop i := i + 1 curc := s.item (i) if escape then escape := False else if curc = '-' then i := i + 1 curc := s.item (i) set_characters (lastc, curc, for_addition) elseif curc = '\' then area.put (for_addition, lastc.code) escape := True else area.put (for_addition, lastc.code) end end lastc := curc end if not escape then area.put (for_addition, lastc.code) end end set_characters (c1, c2: CHARACTER; for_addition: BOOLEAN) -- Set or unset (depending on `for_addition') the characters -- between `c1' and `c2' to the set (bounds included). -- Do nothing if c2 is before c1. local i1, i2: INTEGER do from i1 := c1.code i2 := c2.code until i1 > i2 loop area.put (for_addition, i1) i1 := i1 + 1 end ensure bounds_set: (c1.code >= c2.code) implies ((area.item (c1.code) = for_addition) and (area.item (c2.code) = for_addition)) end note copyright: "Copyright (c) 1984-2006, Eiffel Software and others" license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" source: "[ Eiffel Software 356 Storke Road, Goleta, CA 93117 USA Telephone 805-685-1006, Fax 805-685-6869 Website http://www.eiffel.com Customer support http://support.eiffel.com ]" end -- class CHARACTER_SET