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
Line 
1Unit StringUtilsUnit;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2006-2007 Ronald Brill (rbri at rbri dot de)
5// This software is released under the GNU Public License - see readme.txt
6
7// Helper functions to work with String and AnsiString
8
9Interface
10
11uses
12 Classes,
13 CharUtilsUnit;
14
15const
16 StrTAB = CharTAB;
17 StrCR = CharCR;
18 StrLF = CharLF;
19 StrCRLF = StrCR + StrLF;
20 StrSingleQuote = '''';
21 StrDoubleQuote = '"';
22
23
24 TYPE
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
41 Function StrEscapeAllCharsBy(const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
42
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:
46 // StrExtractStrings('1x2x3\x4', 'x', '\') ->
47 // returns 4 strings: '1', '', '2' and '3x4'
48 Procedure StrExtractStrings(var aResult : TStrings; const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
49
50 // same as StrExtractStrings but ignores empty strings
51 Procedure StrExtractStringsIgnoreEmpty(var aResult : TStrings; const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
52
53 // removes all occurences of char from aSetOfChars from the beginning
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
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
68 // Returns the aCount leftmost chars of aString
69 Function StrLeft(const aString : String; const aCount : Integer) : String;
70
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
77 // Returns a copy of the string starting at aPos
78 Function StrSubstringFrom(const aReceiver: String; const aPos : Integer) : String;
79
80 // returns true if the String starts with the provided one
81 // this is case SENSITIVE
82 Function StrStartsWith(const aReceiver: String; const aStartString: String): Boolean;
83
84 // returns true if the String starts with the provided one
85 // this is case INsensitive
86 Function StrStartsWithIgnoringCase(const aReceiver: String; const aStartString: String): Boolean;
87
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
92 // returns true if the String ends with the provided one
93 // this is case INsensitive
94 Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
95
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
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
105 Function BoolToStr(const aBoolean : boolean ): string;
106
107 // Returns aString enclosed in double quotes
108 Function StrInDoubleQuotes(const aString : String) : String;
109
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 );
113
114
115 // returns the position of aPart in aString
116 // case insensitive
117 Function CaseInsensitivePos(const aPart: String; const aString: String ): longint;
118
119
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
143Implementation
144
145 uses
146 SysUtils,
147 DebugUnit;
148
149 constructor TSerializableStringList.Create;
150 begin
151 LogEvent(LogObjConstDest, 'TSerializableStringList createdestroy');
152
153 inherited Create;
154 stringList := TStringList.Create;
155 end;
156
157
158 destructor TSerializableStringList.Destroy;
159 begin
160 LogEvent(LogObjConstDest, 'TSerializableStringList destroy');
161 if Nil <> stringList then stringList.Destroy;
162
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 := '';
188 for i := 0 to stringList.count-1 do
189 begin
190 if (i > 0) then result := result + '&';
191 result := result + StrEscapeAllCharsBy(stringList[i], ['&'], '\');
192 end;
193 end;
194
195
196 PROCEDURE TSerializableStringList.readValuesFromSerializedString(const aSerializedString : String);
197 Begin
198 if (length(aSerializedString) < 1) then exit;
199
200 LogEvent(LogObjConstDest, 'readValuesFromSerializedString');
201 stringList.Destroy;
202 LogEvent(LogObjConstDest, 'readValuesFromSerializedString destroy done');
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;
212 Var
213 i : Integer;
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
230 Procedure PrivateStrExtractStrings( Var aResult: TStrings;
231 const aReceiver: String;
232 const aSetOfChars: TSetOfChars;
233 const anEscapeChar: char;
234 const anIgnoreEmptyFlag : boolean);
235 Var
236 i : Integer;
237 tmpChar,tmpNextChar : Char;
238 tmpPart: String;
239 Begin
240 if (length(aReceiver) < 1) then exit;
241
242 tmpPart := '';
243
244 i := 1;
245 while i <= length(aReceiver) do
246 begin
247 tmpChar := aReceiver[i];
248 if i < length(aReceiver) then
249 tmpNextChar := aReceiver[i+1]
250 else
251 tmpNextChar := #0;
252
253 if (tmpChar = anEscapeChar) and (tmpNextChar = anEscapeChar) then
254 begin
255 tmpPart := tmpPart + anEscapeChar;
256 i := i + 2;
257 end
258 else
259 if (tmpChar = anEscapeChar) and (tmpNextChar IN aSetOfChars) then
260 begin
261 tmpPart := tmpPart + tmpNextChar;
262 i := i + 2;
263 end
264 else
265 if (tmpChar IN aSetOfChars) then
266 begin
267 if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
268 begin
269 aResult.add(tmpPart);
270 end;
271 tmpPart := '';
272 i := i + 1;
273 end
274 else
275 begin
276 tmpPart := tmpPart + tmpChar;
277 i := i + 1;
278 end;
279 end;
280
281 if (NOT anIgnoreEmptyFlag) OR ('' <> tmpPart) then
282 begin
283 aResult.add(tmpPart);
284 end;
285 end;
286
287
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
302 tmpLength : integer;
303 i : integer;
304 Begin
305 tmpLength := Length(aReceiver);
306
307 if 1 > tmpLength then
308 begin
309 result := aReceiver;
310 exit;
311 end;
312
313 i := 1;
314 // mem optimization
315 if aReceiver[i] in aSetOfChars then
316 begin
317 while i <= tmpLength do
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
335 i : integer;
336 Begin
337 i := Length(aReceiver);
338
339 if 1 > i then
340 begin
341 result := aReceiver;
342 exit;
343 end;
344
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
364 Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
365 Var
366 i,j : integer;
367 tmpNeedCopy : boolean;
368 Begin
369 j := Length(aReceiver);
370
371 if 1 > j then
372 begin
373 result := aReceiver;
374 exit;
375 end;
376
377 tmpNeedCopy := false;
378 i := 1;
379 while i < j do
380 begin
381 if aReceiver[i] in aSetOfChars then
382 begin
383 inc(i);
384 tmpNeedCopy := true;
385 end
386 else
387 begin
388 break;
389 end;
390 end;
391
392 while j >= i do
393 begin
394 if aReceiver[j] in aSetOfChars then
395 begin
396 dec(j);
397 tmpNeedCopy := true;
398 end
399 else
400 begin
401 break;
402 end;
403 end;
404
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;
413 end;
414
415
416 Function StrTrim(const aReceiver: String): String;
417 Begin
418 result := StrTrimChars(aReceiver, [' ']);
419 end;
420
421
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
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
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
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
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
529 begin
530 result := false;
531 exit;
532 end;
533 dec(tmpMatchPos);
534 dec(tmpStringPos);
535 end;
536
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
546 tmpStringPos := length(aReceiver);
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
557 if upcase(aReceiver[tmpStringPos]) <> upcase(anEndString[tmpMatchPos]) then
558 begin
559 result := false;
560 exit;
561 end;
562 dec(tmpMatchPos);
563 dec(tmpStringPos);
564 end;
565
566 result := true;
567 end;
568
569
570 Function StrEqualIgnoringCase(const aReceiver: String; const aSecondString: String): Boolean;
571 begin
572 Result := CompareText(aReceiver, aSecondString) = 0;
573 end;
574
575
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
611 Function BoolToStr(const aBoolean : boolean ): string;
612 begin
613 if aBoolean then
614 Result := 'True'
615 else
616 Result := 'False';
617 end;
618
619
620 Function StrInDoubleQuotes(const aString : String) : String;
621 begin
622 Result := StrDoubleQuote + aString + StrDoubleQuote;
623 end;
624
625
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;
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
996END.
Note: See TracBrowser for help on using the repository browser.