source: trunk/NewView/StringUtilsUnit.pas@ 123

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

format fixes

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