source: trunk/NewView/StringUtilsUnit.pas@ 110

Last change on this file since 110 was 110, checked in by RBRi, 18 years ago

AnsiString functins added

  • Property svn:eol-style set to native
File size: 23.3 KB
RevLine 
[35]1Unit StringUtilsUnit;
2
3// NewView - a new OS/2 Help Viewer
[75]4// Copyright 2006-2007 Ronald Brill (rbri at rbri dot de)
5// This software is released under the GNU Public License - see readme.txt
[35]6
[110]7// Helper functions to work with String and AnsiString
[35]8
9Interface
10
11uses
[110]12 Classes,
13 CharUtilsUnit;
[35]14
[43]15const
[110]16 StrTAB = CharTAB;
17 StrCR = CharCR;
18 StrLF = CharLF;
[43]19 StrCRLF = StrCR + StrLF;
[106]20 StrSingleQuote = '''';
21 StrDoubleQuote = '"';
[43]22
23
24 TYPE
[35]25 TSerializableStringList = class
26 private
27 stringList : TStringList;
28
29 public
30 CONSTRUCTOR Create;
31 DESTRUCTOR Destroy; override;
32 FUNCTION getCount : LongInt;
33 PROCEDURE add(const aString : String);
34 FUNCTION get(const anIndex : LongInt) : String;
35 FUNCTION getSerializedString : String;
36 PROCEDURE readValuesFromSerializedString(const aSerializedString : String);
37 end;
38
39 // prefices all occurences of one of the chars in aStringWithChars with anEscape char
40 // if the escapeChar itself is found, then it is doubled
[43]41 Function StrEscapeAllCharsBy(Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
[35]42
[43]43 // Extract all fields in a String given a set of delimiter characters and
44 // an optional escape character usable to escape field delimits.
45 // Example:
[102]46 // StrExtractStrings('1x2x3\x4', 'x', '\') ->
47 // returns 4 strings: '1', '', '2' and '3x4'
[82]48 Procedure StrExtractStrings(Var aResult : TStrings; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
[43]49
[82]50 // same as StrExtractStrings but ignores empty strings
51 Procedure StrExtractStringsIgnoreEmpty(Var aResult : TStrings; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
52
[43]53 // removes all occurences of char from aSetOfChars from the beginning
[82]54 // of a String.
55 Function StrTrimLeftChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
56
57 // removes all occurences of char from aSetOfChars from the end
58 // of a String.
59 Function StrTrimRightChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
60
61 // removes all occurences of char from aSetOfChars from the beginning
[43]62 // end the end of a String.
63 Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
64
65 // removes all blanks from beginning and end
66 Function StrTrim(const aReceiver: String): String;
67
[82]68 // Returns the aCount leftmost chars of aString
69 Function StrLeft(const aString : String; const aCount : Integer) : String;
70
[102]71 // Returns a copy of the string without aCount chars from right
72 Function StrLeftWithout(const aString : String; const aCount : Integer) : String;
73
74 // Returns a copy of the string including all characters until one from aSetOfChars found
75 Function StrLeftUntil(const aReceiver: String; const aSetOfChars: TSetOfChars) : String;
76
[105]77 // returns true if the String starts with the provided one
[102]78 // this is case SENSITIVE
79 Function StrStartsWith(const aReceiver: String; const aStartString: String): Boolean;
80
[105]81 // returns true if the String starts with the provided one
[102]82 // this is case INsensitive
83 Function StrStartsWithIgnoringCase(const aReceiver: String; const aStartString: String): Boolean;
84
[43]85 // returns true if the String ends with the provides one
86 // this is case SENSITIVE
87 Function StrEndsWith(const aReceiver: String; const anEndString: String): Boolean;
88
[105]89 // returns true if the String ends with the provided one
[43]90 // this is case INsensitive
[102]91 Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
[43]92
[105]93 // returns true if the Strings are the same
94 // this is case INsensitive
95 Function StrEqualIgnoringCase(const aReceiver: String; const aSecondString: String): Boolean;
96
[68]97 // the IntToStr generates wrong results
98 // in normal cases IntToStr returns a negative value
99 // and somtimes completly wrong values
100 Function LongWordToStr(const aLongWord: LongWord) : String;
101
[65]102 Function BoolToStr(const aBoolean : boolean ): string;
[43]103
[102]104 // Returns aString enclosed in double quotes
105 Function StrInDoubleQuotes(const aString : String) : String;
[65]106
[106]107 // Extract all fields in a String delimited by whitespace (blank or tab).
108 // use double quotes if you need blanks in the strings
109 Procedure StrExtractStringsQuoted(Var aResult: TStrings; const aReceiver: String );
[102]110
[110]111
112 // returns the position of aPart in aString
113 // case insensitive
114 Function CaseInsensitivePos(const aPart: String; const aString: String ): longint;
115
116 // --------------------
117 // ---- AnsiString ----
118 // --------------------
119
120
121 // removes all occurences of char from aSetOfChars from the beginning
122 // of a String.
123 Function AnsiStrTrimLeftChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
124
125 // removes all occurences of char from aSetOfChars from the end
126 // of a String.
127 Function AnsiStrTrimRightChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
128
129 // removes all occurences of char from aSetOfChars from the beginning
130 // end the end of a String.
131 Function AnsiStrTrimChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
132
133 // removes all blanks from beginning and end
134 Function AnsiStrTrim(const aReceiver: AnsiString): AnsiString;
135
136
137
138
[35]139Implementation
140
[65]141 uses
[105]142 SysUtils,
[65]143 DebugUnit;
144
[35]145 constructor TSerializableStringList.Create;
146 begin
[65]147 LogEvent(LogObjConstDest, 'TSerializableStringList createdestroy');
148
[35]149 inherited Create;
150 stringList := TStringList.Create;
151 end;
152
153
154 destructor TSerializableStringList.Destroy;
155 begin
[65]156 LogEvent(LogObjConstDest, 'TSerializableStringList destroy');
157 if Nil <> stringList then stringList.Destroy;
158
[35]159 inherited Destroy;
160 end;
161
162
163 FUNCTION TSerializableStringList.getCount : LongInt;
164 begin
165 result := stringList.count;
166 end;
167
168
169 PROCEDURE TSerializableStringList.add(const aString : String);
170 begin
171 stringList.add(aString);
172 end;
173
174 FUNCTION TSerializableStringList.get(const anIndex : LongInt) : String;
175 begin
176 result := stringList[anIndex];
177 end;
178
179 FUNCTION TSerializableStringList.getSerializedString : String;
180 Var
181 i : Integer;
182 begin
183 result := '';
[82]184 for i := 0 to stringList.count-1 do
[35]185 begin
186 if (i > 0) then result := result + '&';
[43]187 result := result + StrEscapeAllCharsBy(stringList[i], ['&'], '\');
[35]188 end;
189 end;
190
191
192 PROCEDURE TSerializableStringList.readValuesFromSerializedString(const aSerializedString : String);
[43]193 Begin
194 if (length(aSerializedString) < 1) then exit;
195
[65]196 LogEvent(LogObjConstDest, 'readValuesFromSerializedString');
197 stringList.Destroy;
198 LogEvent(LogObjConstDest, 'readValuesFromSerializedString destroy done');
[43]199 stringList := TStringList.Create;
200 StrExtractStrings(stringList, aSerializedString, ['&'], '\');
201 end;
202
203
204 // ----------------------------------------------------------
205
206
207 Function StrEscapeAllCharsBy(Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
[35]208 Var
209 i : Integer;
[43]210 tmpChar : Char;
211 Begin
212 Result := '';
213
214 for i := 1 To length(aReceiver) do
215 begin
216 tmpChar := aReceiver[i];
217
218 if (tmpChar = anEscapeChar) or (tmpChar IN aSetOfChars) then
219 result := result + anEscapeChar + tmpChar
220 else
221 result := result + tmpChar;
222 end;
223 end;
224
225
[82]226 Procedure PrivateStrExtractStrings( Var aResult: TStrings;
227 const aReceiver: String;
228 const aSetOfChars: TSetOfChars;
229 const anEscapeChar: char;
230 const anIgnoreEmptyFlag : boolean);
[43]231 Var
232 i : Integer;
[35]233 tmpChar,tmpNextChar : Char;
234 tmpPart: String;
[43]235 Begin
236 if (length(aReceiver) < 1) then exit;
[35]237
238 tmpPart := '';
239
240 i := 1;
[43]241 while i <= length(aReceiver) do
[35]242 begin
[43]243 tmpChar := aReceiver[i];
244 if i < length(aReceiver) then
245 tmpNextChar := aReceiver[i+1]
[35]246 else
247 tmpNextChar := #0;
248
[43]249 if (tmpChar = anEscapeChar) and (tmpNextChar = anEscapeChar) then
[35]250 begin
[43]251 tmpPart := tmpPart + anEscapeChar;
[35]252 i := i + 2;
253 end
254 else
[43]255 if (tmpChar = anEscapeChar) and (tmpNextChar IN aSetOfChars) then
[35]256 begin
[43]257 tmpPart := tmpPart + tmpNextChar;
[35]258 i := i + 2;
259 end
260 else
[43]261 if (tmpChar IN aSetOfChars) then
[35]262 begin
[82]263 if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
264 begin
265 aResult.add(tmpPart);
266 end;
[35]267 tmpPart := '';
268 i := i + 1;
269 end
270 else
271 begin
272 tmpPart := tmpPart + tmpChar;
273 i := i + 1;
274 end;
275 end;
[82]276
277 if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
278 begin
279 aResult.add(tmpPart);
280 end;
[35]281 end;
282
283
[82]284 Procedure StrExtractStrings(Var aResult: TStrings; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
285 Begin
286 PrivateStrExtractStrings(aResult, aReceiver, aSetOfChars, anEscapeChar, false);
287 end;
288
289
290 Procedure StrExtractStringsIgnoreEmpty(Var aResult: TStrings; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
291 Begin
292 PrivateStrExtractStrings(aResult, aReceiver, aSetOfChars, anEscapeChar, true);
293 end;
294
295
296 Function StrTrimLeftChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
297 Var
[110]298 tmpLength : integer;
299 i : integer;
[82]300 Begin
[110]301 tmpLength := Length(aReceiver);
302
303 if 1 > tmpLength then
304 begin
305 result := aReceiver;
306 exit;
307 end;
308
[82]309 i := 1;
310 // mem optimization
311 if aReceiver[i] in aSetOfChars then
312 begin
[110]313 while i <= tmpLength do
[82]314 begin
315 if aReceiver[i] in aSetOfChars then
316 inc(i)
317 else
318 break;
319 end;
320 result := Copy(aReceiver, i, Length(aReceiver)-i+1);
321 end
322 else
323 begin
324 result := aReceiver;
325 end;
326 end;
327
328
329 Function StrTrimRightChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
330 Var
[110]331 i : integer;
[82]332 Begin
333 i := Length(aReceiver);
334
[110]335 if 1 > i then
336 begin
337 result := aReceiver;
338 exit;
339 end;
340
[82]341 // mem optimization
342 if aReceiver[i] in aSetOfChars then
343 begin
344 while i > 0 do
345 begin
346 if aReceiver[i] in aSetOfChars then
347 dec(i)
348 else
349 break;
350 end;
351 result := Copy(aReceiver, 1, i);
352 end
353 else
354 begin
355 result := aReceiver;
356 end;
357 end;
358
359
[43]360 Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
[35]361 Var
[110]362 i,j : integer;
[82]363 tmpNeedCopy : boolean;
[35]364 Begin
[110]365 j := Length(aReceiver);
366
367 if 1 > j then
368 begin
369 result := aReceiver;
370 exit;
371 end;
372
[82]373 tmpNeedCopy := false;
[43]374 i := 1;
[110]375 while i < j do
[43]376 begin
377 if aReceiver[i] in aSetOfChars then
[82]378 begin
379 inc(i);
380 tmpNeedCopy := true;
381 end
382 else
383 begin
384 break;
385 end;
[43]386 end;
[35]387
[43]388 while j >= i do
[35]389 begin
[43]390 if aReceiver[j] in aSetOfChars then
[82]391 begin
392 dec(j);
393 tmpNeedCopy := true;
394 end
[43]395 else
[82]396 begin
[43]397 break;
[82]398 end;
[43]399 end;
400
[82]401 if tmpNeedCopy then
402 begin
403 result := Copy(aReceiver, i, j-i+1);
404 end
405 else
406 begin
407 result := aReceiver;
408 end;
[43]409 end;
410
411
412 Function StrTrim(const aReceiver: String): String;
413 Begin
414 result := StrTrimChars(aReceiver, [' ']);
415 end;
416
417
[82]418 Function StrLeft(const aString : String; const aCount : Integer) : String;
419 Begin
420 if aCount >= Length(aString) then
421 Result := aString
422 else
423 Result := copy(aString, 1, aCount);
424 end;
425
426
[102]427 Function StrLeftWithout(const aString : String; const aCount : Integer) : String;
428 Begin
429 Result:= copy(aString, 1, length(aString) - aCount );
430 End;
431
432
433 Function StrLeftUntil(const aReceiver: String; const aSetOfChars: TSetOfChars) : String;
434 Var
435 i : integer;
436 Begin
437 Result := aReceiver;
438
439 for i := 1 To Length(aReceiver) do
440 begin
441 if aReceiver[i] in aSetOfChars then
442 begin
443 Result := Copy(aReceiver, 1, i-1 );
444 break;
445 end;
446 end;
447 end;
448
449
450 Function StrStartsWith(const aReceiver: String; const aStartString: String) : Boolean;
451 Var
452 tmpStringPos : integer;
453 tmpStartStringLength : integer;
454 Begin
455 tmpStartStringLength := Length(aStartString);
456
457 if Length(aReceiver) < tmpStartStringLength then
458 begin
459 result := false;
460 exit;
461 end;
462
463 for tmpStringPos := 1 to tmpStartStringLength do
464 begin
465 if aReceiver[tmpStringPos] <> aStartString[tmpStringPos] then
466 begin
467 result := false;
468 exit;
469 end;
470 end;
471
472 result := true;
473 end;
474
475
476 Function StrStartsWithIgnoringCase(const aReceiver: String; const aStartString: String) : Boolean;
477 Var
478 tmpStringPos : integer;
479 tmpStartStringLength : integer;
480 Begin
481 tmpStartStringLength := Length(aStartString);
482
483 if Length(aReceiver) < tmpStartStringLength then
484 begin
485 result := false;
486 exit;
487 end;
488
489 for tmpStringPos := 1 to tmpStartStringLength do
490 begin
491 if UpCase(aReceiver[tmpStringPos]) <> UpCase(aStartString[tmpStringPos]) then
492 begin
493 result := false;
494 exit;
495 end;
496 end;
497
498 result := true;
499 end;
500
501
[43]502 Function StrEndsWith(const aReceiver: String; const anEndString: String): Boolean;
503 Var
504 tmpStringPos : Longint;
505 tmpMatchPos : Longint;
506 Begin
507 tmpStringPos := length(aReceiver);
508 tmpMatchPos := length(anEndString);
509
510 if tmpMatchPos > tmpStringPos then
511 begin
512 result := false;
513 exit;
514 end;
515
516 while tmpMatchPos > 0 do
517 begin
518 if aReceiver[tmpStringPos] <> anEndString[tmpMatchPos] then
[35]519 begin
[43]520 result := false;
521 exit;
522 end;
523 dec(tmpMatchPos);
524 dec(tmpStringPos);
525 end;
[35]526
[43]527 result := true;
528 end;
529
530
531 Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
532 Var
533 tmpStringPos : Longint;
534 tmpMatchPos : Longint;
535 Begin
[102]536 tmpStringPos := length(aReceiver);
[43]537 tmpMatchPos := length(anEndString);
538
539 if tmpMatchPos > tmpStringPos then
540 begin
541 result := false;
542 exit;
543 end;
544
545 while tmpMatchPos > 0 do
546 begin
[102]547 if upcase(aReceiver[tmpStringPos]) <> upcase(anEndString[tmpMatchPos]) then
[43]548 begin
549 result := false;
550 exit;
[35]551 end;
[43]552 dec(tmpMatchPos);
553 dec(tmpStringPos);
[35]554 end;
[43]555
556 result := true;
[35]557 end;
558
[102]559
[105]560 Function StrEqualIgnoringCase(const aReceiver: String; const aSecondString: String): Boolean;
561 begin
562 Result := CompareText(aReceiver, aSecondString) = 0;
563 end;
564
565
[68]566 Function LongWordToStr(const aLongWord: LongWord) : String;
567 Var
568 l : LongWord;
569 i : Integer;
570 Begin
571 Result := '';
572 l := aLongWord;
573
574 if l = 0 then
575 begin
576 result := '0';
577 exit;
578 end;
579
580 while l > 0 do
581 begin
582 i := l mod 10;
583 l := l div 10;
584 Case i of
585 0 : result := '0' + result;
586 1 : result := '1' + result;
587 2 : result := '2' + result;
588 3 : result := '3' + result;
589 4 : result := '4' + result;
590 5 : result := '5' + result;
591 6 : result := '6' + result;
592 7 : result := '7' + result;
593 8 : result := '8' + result;
594 9 : result := '9' + result;
595 end;
596 end;
597
598 end;
599
600
[65]601 Function BoolToStr(const aBoolean : boolean ): string;
602 begin
603 if aBoolean then
604 Result := 'True'
605 else
606 Result := 'False';
607 end;
608
[106]609
[102]610 Function StrInDoubleQuotes(const aString : String) : String;
611 begin
[106]612 Result := StrDoubleQuote + aString + StrDoubleQuote;
[102]613 end;
614
615
[106]616 Procedure StrExtractStringsQuoted(Var aResult: TStrings; const aReceiver: String );
617 Var
618 tmpState : (WHITESPACE, INSIDE, START_QUOTE, INSIDE_QUOTED, INSIDE_QUOTED_START_QUOTE);
619 tmpCurrentParsePosition : Integer;
620 tmpCurrentChar : Char;
621 tmpPart : String;
622
623 Begin
624 if (length(aReceiver) < 1) then exit;
625
626 tmpState := WHITESPACE;
627 tmpPart := '';
628
629 tmpCurrentParsePosition := 1;
630
631 for tmpCurrentParsePosition:=1 to length(aReceiver) do
632 begin
633 tmpCurrentChar := aReceiver[tmpCurrentParsePosition];
634
635 Case tmpCurrentChar of
636 ' ', StrTAB :
637 begin
638
639 Case tmpState of
640
641 WHITESPACE :
642 begin
643 // nothing
644 end;
645
646 INSIDE :
647 begin
648 aResult.add(tmpPart);
649 tmpPart := '';
650 tmpState := WHITESPACE;
651 end;
652
653 INSIDE_QUOTED :
654 begin
655 tmpPart := tmpPart + tmpCurrentChar;
656 end;
657
658 START_QUOTE :
659 begin
660 tmpPart := tmpPart + tmpCurrentChar;
661 tmpState := INSIDE_QUOTED;
662 end;
663
664 INSIDE_QUOTED_START_QUOTE :
665 begin
666 aResult.add(tmpPart);
667 tmpPart := '';
668 tmpState := WHITESPACE;
669 end;
670 end;
671 end;
672
673 StrDoubleQuote :
674 begin
675
676 Case tmpState of
677
678 WHITESPACE :
679 begin
680 tmpState := START_QUOTE;
681 end;
682
683 INSIDE :
684 begin
685 aResult.add(tmpPart);
686 tmpPart := '';
687 tmpState := START_QUOTE;
688 end;
689
690 INSIDE_QUOTED :
691 begin
692 tmpState := INSIDE_QUOTED_START_QUOTE;
693 end;
694
695 START_QUOTE :
696 begin
697 tmpState := INSIDE_QUOTED_START_QUOTE;
698 end;
699
700 INSIDE_QUOTED_START_QUOTE :
701 begin
702 tmpPart := tmpPart + tmpCurrentChar;
703 tmpState := INSIDE_QUOTED;
704 end;
705 end;
706 end;
707
708 else
709 begin
710 Case tmpState of
711
712 WHITESPACE :
713 begin
714 tmpPart := tmpPart + tmpCurrentChar;
715 tmpState := INSIDE;
716 end;
717
718 INSIDE, INSIDE_QUOTED :
719 begin
720 tmpPart := tmpPart + tmpCurrentChar;
721 end;
722
723 START_QUOTE :
724 begin
725 tmpPart := tmpPart + tmpCurrentChar;
726 tmpState := INSIDE_QUOTED;
727 end;
728
729 INSIDE_QUOTED_START_QUOTE :
730 begin
731 aResult.add(tmpPart);
732 tmpPart := tmpCurrentChar;
733 tmpState := INSIDE;
734 end;
735 end;
736 end;
737
738 end;
739 end;
740
741 Case tmpState of
742 WHITESPACE, START_QUOTE : {nothing to do};
743
744 INSIDE, INSIDE_QUOTED, INSIDE_QUOTED_START_QUOTE :
745 begin
746 aResult.add(tmpPart);
747 end;
748 end;
749 end;
[110]750
751
752 Function CaseInsensitivePos(const aPart: String; const aString: String) : longint;
753 Var
754 EndOfPart: longword;
755 Begin
756 // Result := Pos(UpperCase(aPart), Uppercase(aString));
757
758 // Aarons assembler version :-)
759 Asm
760 //Locals:
761 //a at [EBP+12]
762 //b at [EBP+8]
763
764 // First get and check lengths
765 MOV ESI, aPart // get address of aPart into ESI
766 MOV CL, [ESI] // get length of aPart
767 CMP CL, 0 // if aPart is empty then return null to simulate the behavior of POS
768 JE !CIP_NoMatch
769
770 MOV EDI, aString // get address of aString into EDI
771 MOV DL, [EDI] // get length of aString
772 CMP CL, DL
773 JBE !CIP_PartFitsInString
774
775 // aParta longer than aString so aPart can't be in aString
776
777 !CIP_NoMatch:
778 MOV EAX, 0
779 LEAVE
780 RETN32 8
781
782 !CIP_PartFitsInString:
783 INC ESI // skip length byte in aPart
784 INC EDI // skip length byte of aString
785
786 // get ending address of b into EDX
787 MOVZX EDX, DL // widen DL
788 ADD EDX, EDI // add start of aString
789
790 // get ending address of a into EndOfA
791 MOVZX ECX, CL // widen CL
792 ADD ECX, ESI // add start of aPart
793 MOV EndOfPart, ECX // store to EndOfPart
794
795 MOV ECX, EDI // set start of current match to start of b
796
797 // ESI: current search point in a
798 // EDI: current search point in b
799 // EDX: end of b
800 // ECX: start of current match
801 // available: eax, ebx
802
803 JMP !CIP_Loop
804
805 !CIP_LoopStart:
806 CMP EDI, EDX
807 JE !CIP_NoMatch // run out of b
808
809 MOV AL, [ESI] // get next char of a
810 INC ESI // next in a
811
812 MOV BL, [EDI] // get next char of b
813 INC EDI // next in b
814
815 // Convert chars to uppercase
816 CMP AL, 97
817 JB !CIP_Upcase1
818 CMP AL, 122
819 JA !CIP_Upcase1
820 SUB AL, 32 // convert lower to upper
821 !CIP_Upcase1:
822
823 CMP BL,97
824 JB !CIP_Upcase2
825 CMP BL,122
826 JA !CIP_Upcase2
827 SUB BL,32 // convert lower to upper
828 !CIP_Upcase2:
829
830 // Compare uppercased chars
831 CMP AL,BL
832 JE !CIP_Loop
833
834 // different.
835
836 // Back to start of match + 1
837 INC ECX // inc start of match
838 MOV EDI, ECX // back to start of match in b
839 MOV ESI, aPart // back to start of aPart
840 INC ESI // skip length
841 JMP !CIP_LoopStart
842
843 !CIP_Loop:
844
845 // same
846 CMP ESI, EndOfPart // have we reached the end of a
847 JB !CIP_LoopStart
848
849 // Match, return position
850 SUB ECX, [EBP+8] // position = ( start of match ) - ( start of b ) + 1
851 MOV EAX, ECX
852 LEAVE
853 RETN32 8
854 end;
855 end;
856
857
858 // --------------------
859 // ---- AnsiString ----
860 // --------------------
861
862
863 Function AnsiStrTrimLeftChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
864 Var
865 tmpLength : integer;
866 i : integer;
867 Begin
868 tmpLength := Length(aReceiver);
869
870 if 1 > tmpLength then
871 begin
872 result := aReceiver;
873 exit;
874 end;
875
876 i := 1;
877 // mem optimization
878 if aReceiver[i] in aSetOfChars then
879 begin
880 while i <= tmpLength do
881 begin
882 if aReceiver[i] in aSetOfChars then
883 inc(i)
884 else
885 break;
886 end;
887 result := AnsiCopy(aReceiver, i, Length(aReceiver)-i+1);
888 end
889 else
890 begin
891 result := aReceiver;
892 end;
893 end;
894
895
896 Function AnsiStrTrimRightChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
897 Var
898 i : integer;
899 Begin
900 i := Length(aReceiver);
901
902 if 1 > i then
903 begin
904 result := aReceiver;
905 exit;
906 end;
907
908 // mem optimization
909 if aReceiver[i] in aSetOfChars then
910 begin
911 while i > 0 do
912 begin
913 if aReceiver[i] in aSetOfChars then
914 dec(i)
915 else
916 break;
917 end;
918 result := AnsiCopy(aReceiver, 1, i);
919 end
920 else
921 begin
922 result := aReceiver;
923 end;
924 end;
925
926
927 Function AnsiStrTrimChars(const aReceiver: AnsiString; const aSetOfChars: TSetOfChars): AnsiString;
928 Var
929 i,j : integer;
930 tmpNeedCopy : boolean;
931 Begin
932 tmpNeedCopy := false;
933
934 j := Length(aReceiver);
935
936 if 1 > j then
937 begin
938 result := aReceiver;
939 exit;
940 end;
941
942 i := 1;
943 while i < j do
944 begin
945 if aReceiver[i] in aSetOfChars then
946 begin
947 inc(i);
948 tmpNeedCopy := true;
949 end
950 else
951 begin
952 break;
953 end;
954 end;
955
956 while j >= i do
957 begin
958 if aReceiver[j] in aSetOfChars then
959 begin
960 dec(j);
961 tmpNeedCopy := true;
962 end
963 else
964 begin
965 break;
966 end;
967 end;
968
969 if tmpNeedCopy then
970 begin
971 result := AnsiCopy(aReceiver, i, j-i+1);
972 end
973 else
974 begin
975 result := aReceiver;
976 end;
977 end;
978
979
980 Function AnsiStrTrim(const aReceiver: AnsiString): AnsiString;
981 Begin
982 result := AnsiStrTrimChars(aReceiver, [' ']);
983 end;
984
985
[35]986END.
Note: See TracBrowser for help on using the repository browser.