home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Programming / sofa / archive / SmallEiffel.lha / SmallEiffel / contrib / lib / case_insensitive_string.e next >
Text File  |  1999-06-05  |  7KB  |  378 lines

  1. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  2. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  3. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  4. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  5. -- this header is kept unaltered, and a notification of the changes is added.
  6. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  7. -- another product.
  8. --
  9. -- This file is copyrighted and maintained by P.M. Hegt
  10. -- E-mail: p_m_hegt@hotmail.com
  11. --
  12.  
  13. indexing
  14.  
  15.     description: "Case-insensitive strings."
  16.  
  17.     author: "P.M. Hegt (mailto: p_m_hegt@hotmail.com)"
  18.  
  19.     copyright: "Freeware. No warranty."
  20.  
  21.     note: "Create a case-insensitive string as follows: %
  22.         % local %
  23.         %    s: CASE_INSENSITIVE_STRING %
  24.         % do %
  25.         %    !! s.make_from_string (%"aBcD%") %
  26.         % end %
  27.         % %
  28.         % Some features are slower because we cannot use the fast %
  29.         % C functions anymore. "
  30.  
  31. class
  32.     CASE_INSENSITIVE_STRING
  33.  
  34. inherit
  35.     STRING
  36.         redefine
  37.             is_equal
  38.         ,    index_of
  39.         ,    index_of_string
  40.         ,    infix "<"
  41.         ,    hash_code
  42.         ,    compare
  43.         ,    occurrences_of
  44.         ,    occurrences
  45.         end
  46.  
  47. creation
  48.     make, copy, blank, from_external, copy_from_string
  49.  
  50. feature -- Modification
  51.  
  52.     copy_from_string (other: STRING) is
  53.             -- Copy `other' onto Current.
  54.         do
  55.             count := other.count;
  56.             if count > 0 then
  57.                 if capacity < count then
  58.                     storage := storage.calloc(count);
  59.                     capacity := count;
  60.                 end;
  61.                 storage.copy_from(other.storage,count-1);
  62.             end;
  63.         ensure then
  64.             count = other.count
  65.         end;
  66.  
  67. feature -- Testing
  68.  
  69.     is_equal(other: like Current): BOOLEAN is
  70.             -- Has Current the same case insensitive text as `other'?
  71.         do
  72.             if Current = other then
  73.                 Result := true
  74.             elseif count = other.count then
  75.                 Result := same_as (other)
  76.             end
  77.         end
  78.  
  79.     index_of (ch: CHARACTER): INTEGER is
  80.         -- Gives the index of the first occurrence `ch' or 
  81.         -- `count + 1' if none.
  82.         local
  83.             c: CHARACTER
  84.         do
  85.             from
  86.                 c := ch.to_lower -- Speed optimization
  87.                 Result := 1
  88.             invariant
  89.                 valid_index (Result)
  90.             variant
  91.                 count - Result
  92.             until
  93.                 not ( Result <= count and c /= item(Result).to_lower)
  94.             loop
  95.                 Result := Result + 1
  96.             end
  97.         ensure
  98.             (Result /= count + 1) implies (item(Result).to_lower = ch.to_lower)
  99.         end;
  100.  
  101.     index_of_string(other: STRING): INTEGER is
  102.             -- Position of the first occurrence of `other'
  103.             -- `count + 1' if none.
  104.         require
  105.             not other.empty
  106.         local
  107.             stop: BOOLEAN
  108.             i1, i2, i3: INTEGER
  109.         do
  110.             from
  111.                 i1 := 1
  112.                 i2 := other.count
  113.                 i3 := i2
  114.                 invariant
  115.                 i3 = i2 - i1 + 1;
  116.             variant
  117.                 count - i1 + 1
  118.             until
  119.                 Result /= 0
  120.             loop
  121.                 if i2 > count then
  122.                     Result := count + 1
  123.                 else
  124.                     from
  125.                         stop := false
  126.                     invariant
  127.                         i3 = i2 - i1 + 1
  128.                     variant
  129.                         (i3 + i2)
  130.                     until
  131.                         stop
  132.                     loop
  133.                         if i3 = 0 then
  134.                             stop := true
  135.                             Result := i1
  136.                         elseif other.item(i3).to_lower /= item(i2).to_lower then
  137.                             stop := true
  138.                         end;
  139.                         i3 := i3 - 1
  140.                         i2 := i2 - 1
  141.                     end
  142.                 end
  143.                 i1 := i1 + 1
  144.                 i3 := other.count
  145.                 i2 := i1 + i3 - 1
  146.             end
  147.         end
  148.  
  149.     occurrences_of, occurrences (ch: CHARACTER): INTEGER is
  150.             -- How many character `ch' in the receiver.
  151.         local
  152.             c: CHARACTER
  153.             i: INTEGER
  154.         do
  155.             from
  156.                 c := ch.to_lower
  157.                 i := 1
  158.             invariant
  159.                 valid_index (i)
  160.                 Result >= 0
  161.             variant
  162.                 count - i
  163.             until
  164.                 not (i <= count)
  165.             loop
  166.                 if item (i).to_lower = c then
  167.                     Result := Result + 1
  168.                 end
  169.  
  170.                 i := i + 1
  171.             end
  172.         ensure
  173.             Result >= 0
  174.         end
  175.  
  176.     infix "<" (other: like Current): BOOLEAN is
  177.             -- Is Current less than `other' ?
  178.         local
  179.             i: INTEGER;
  180.         do
  181.             from  
  182.                 i := 1;
  183.             until
  184.                 count < i or else other.count < i 
  185.                     or else item(i).to_lower /= other.item(i).to_lower
  186.             loop
  187.                 i := i + 1;
  188.             end;
  189.  
  190.             if count < i then
  191.                 Result := other.count >= i;
  192.             elseif other.count < i then
  193.                 Result := false;
  194.             else
  195.                 Result := item(i).to_lower < other.item(i).to_lower;
  196.             end;
  197.         end;
  198.  
  199.     compare (other: like Current): INTEGER is
  200.             -- Compare `Current' with `other'.
  201.             -- `<'  <==> `Result < 0'
  202.             -- `>'  <==> `Result > 0'
  203.             -- Otherwise `Result = 0'.
  204.         local
  205.             i: INTEGER;
  206.         do
  207.             from  
  208.                 i := 1;
  209.             until
  210.                 count < i or else other.count < i 
  211.                     or else item(i).to_lower /= other.item(i).to_lower
  212.             loop
  213.                 i := i + 1;
  214.             end;
  215.  
  216.             if count < i then
  217.                 if other.count < i then
  218.                     Result := 0;
  219.                 else
  220.                     Result := -1;
  221.                 end;
  222.             elseif other.count < i then
  223.                 Result := +1;
  224.             elseif item(i).to_lower < other.item(i).to_lower then
  225.                 Result := -1;
  226.             else
  227.                 Result := +1;
  228.             end;
  229.         end;
  230.  
  231.     hash_code: INTEGER is
  232.             -- Case insensitive has code.
  233.         local
  234.             i: INTEGER
  235.         do
  236.             i := count
  237.             if i > 5 then
  238.                 Result := i * item(i).to_lower.code
  239.                 i := 5
  240.             end
  241.             from until i <= 0 loop
  242.                 Result := Result + i + item(i).to_lower.code
  243.                 i := i - 1
  244.             end
  245.             Result := Result * count
  246.         end
  247.  
  248.     has_suffix(s: STRING): BOOLEAN is
  249.             -- True if suffix of Current is `s'.
  250.         require
  251.             s /= Void
  252.         local
  253.             i1, i2: INTEGER
  254.         do
  255.             if s.count <= count then
  256.                 from  
  257.                    i1 := count - s.count + 1;
  258.                 i2 := 1;
  259.                 until
  260.                     i1 > count or else
  261.                     i2 > s.count or else
  262.                     item(i1).to_lower /= s.item(i2).to_lower
  263.                 loop
  264.                     i1 := i1 + 1
  265.                     i2 := i2 + 1
  266.                 end
  267.  
  268.                 Result := i1 > count
  269.             end
  270.         end
  271.  
  272.     has_prefix (p: STRING): BOOLEAN is
  273.             -- True if prefix of Current is `p'.
  274.         require
  275.             p /= Void
  276.         local
  277.             i: INTEGER
  278.         do
  279.             if p.count <= count then
  280.                 from  
  281.                     i := p.count
  282.                 until
  283.                    i = 0 or else item(i).to_lower /= p.item(i).to_lower
  284.                 loop
  285.                     i := i - 1
  286.                 end
  287.  
  288.                 Result := i = 0
  289.             end
  290.         end
  291.  
  292.     substring_index (other: STRING; start: INTEGER): INTEGER is
  293.             -- Position of first occurrence of `other' at or after 
  294.             -- `start';
  295.             -- 0 if none.
  296.         require
  297.             start_large_enough: start >= 1;
  298.             start_small_enough: start <= count;
  299.             string_exist: other /= Void
  300.         local
  301.             i, s: INTEGER;
  302.         do
  303.             from
  304.                 s := start;
  305.             until
  306.                 Result /= 0 or else (s + other.count - 1) > count
  307.             loop
  308.                 from
  309.                     i := 1
  310.                 until
  311.                     i > other.count or else item(s + i - 1).to_lower /= other.item(i).to_lower
  312.                 loop
  313.                     i := i + 1
  314.                 end
  315.  
  316.                 if i > other.count then
  317.                     Result := s
  318.                 else
  319.                     s := s + 1
  320.                 end
  321.             end
  322.         end
  323.  
  324. feature -- Element change
  325.  
  326.     replace_all (old_character, new_character: like item) is
  327.             -- Replace all occurences of the element `old_character' by 
  328.             -- `new_character'.
  329.         local
  330.             i: INTEGER
  331.             c: CHARACTER
  332.         do
  333.             from
  334.                 c := old_character.to_lower -- Speed optimization
  335.                 i := 1
  336.             invariant
  337.                 valid_index (i)
  338.             variant
  339.                 count - i
  340.             until
  341.                 not (i <= count)
  342.             loop
  343.                 if item (i).to_lower = c then
  344.                     put (new_character, i)
  345.                 end
  346.             end
  347.         ensure
  348.             count = old count;
  349.             occurrences_of (old_character) = 0
  350.         end
  351.  
  352.     remove_all_occurrences (ch: CHARACTER) is
  353.             -- Remove all occurrences of `ch'.
  354.         local
  355.             c: CHARACTER
  356.             i, j: INTEGER;
  357.         do
  358.             from
  359.                 c := c.to_lower
  360.                 i := 1
  361.                 j := 1
  362.             until
  363.                 i > count
  364.             loop
  365.                 if item (i).to_lower /= c then
  366.                     put (item (i), j)
  367.                     j := j + 1
  368.                 end
  369.                 i := i + 1
  370.             end
  371.  
  372.             count := j - 1;
  373.         ensure
  374.             count = old count - old occurrences_of (ch)
  375.         end
  376.  
  377. end -- class CASE_INSENSITIVE_STRING
  378.