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