| 1 | Unit StringUtilsUnit;
 | 
|---|
| 2 | 
 | 
|---|
| 3 | // NewView - a new OS/2 Help Viewer
 | 
|---|
| 4 | // Copyright 2006 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 strings
 | 
|---|
| 8 | 
 | 
|---|
| 9 | Interface
 | 
|---|
| 10 | 
 | 
|---|
| 11 | uses
 | 
|---|
| 12 |  Classes;
 | 
|---|
| 13 | 
 | 
|---|
| 14 | const
 | 
|---|
| 15 |   StrCR = chr(13);
 | 
|---|
| 16 |   StrLF = chr(10);
 | 
|---|
| 17 |   StrCRLF = StrCR + StrLF;
 | 
|---|
| 18 | 
 | 
|---|
| 19 | 
 | 
|---|
| 20 |   TYPE
 | 
|---|
| 21 |      TSerializableStringList = class
 | 
|---|
| 22 |      private
 | 
|---|
| 23 |        stringList : TStringList;
 | 
|---|
| 24 | 
 | 
|---|
| 25 |      public
 | 
|---|
| 26 |        CONSTRUCTOR Create;
 | 
|---|
| 27 |        DESTRUCTOR Destroy; override;
 | 
|---|
| 28 |        FUNCTION getCount : LongInt;
 | 
|---|
| 29 |        PROCEDURE add(const aString : String);
 | 
|---|
| 30 |        FUNCTION get(const anIndex : LongInt) : String;
 | 
|---|
| 31 |        FUNCTION getSerializedString : String;
 | 
|---|
| 32 |        PROCEDURE readValuesFromSerializedString(const aSerializedString : String);
 | 
|---|
| 33 |   end;
 | 
|---|
| 34 | 
 | 
|---|
| 35 |   TYPE
 | 
|---|
| 36 |     TSetOfChars = set of char;
 | 
|---|
| 37 | 
 | 
|---|
| 38 |   // prefices all occurences of one of the chars in aStringWithChars with anEscape char
 | 
|---|
| 39 |   // if the escapeChar itself is found, then it is doubled
 | 
|---|
| 40 |   Function StrEscapeAllCharsBy(Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
 | 
|---|
| 41 | 
 | 
|---|
| 42 |   // Extract all fields in a String given a set of delimiter characters and
 | 
|---|
| 43 |   // an optional escape character usable to escape field delimits.
 | 
|---|
| 44 |   // Example:
 | 
|---|
| 45 |   //     StrExtractStrings('1x2x3\x4', "x", '\') ->
 | 
|---|
| 46 |   //     returns 4 strings: "1", "", "2" and "3x4"
 | 
|---|
| 47 |   Procedure StrExtractStrings(Var aResult : TStringList; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
 | 
|---|
| 48 | 
 | 
|---|
| 49 |   // removes all occurences of char from aSetOfChars from the beginning
 | 
|---|
| 50 |   // end the end of a String.
 | 
|---|
| 51 |   Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
| 52 | 
 | 
|---|
| 53 |   // removes all blanks from beginning and end
 | 
|---|
| 54 |   Function StrTrim(const aReceiver: String): String;
 | 
|---|
| 55 | 
 | 
|---|
| 56 |   // returns true if the String ends with the provides one
 | 
|---|
| 57 |   // this is case SENSITIVE
 | 
|---|
| 58 |   Function StrEndsWith(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
| 59 | 
 | 
|---|
| 60 |   // returns true if the String ends with the provides one
 | 
|---|
| 61 |   // this is case INsensitive
 | 
|---|
| 62 |   Function StrEndsWithIgnoringCase(const aString: String; const anEndString: String): Boolean;
 | 
|---|
| 63 | 
 | 
|---|
| 64 | 
 | 
|---|
| 65 | Implementation
 | 
|---|
| 66 | 
 | 
|---|
| 67 |   constructor TSerializableStringList.Create;
 | 
|---|
| 68 |   begin
 | 
|---|
| 69 |     inherited Create;
 | 
|---|
| 70 |     stringList := TStringList.Create;
 | 
|---|
| 71 |   end;
 | 
|---|
| 72 | 
 | 
|---|
| 73 | 
 | 
|---|
| 74 |   destructor TSerializableStringList.Destroy;
 | 
|---|
| 75 |   begin
 | 
|---|
| 76 |     stringList.Destroy;
 | 
|---|
| 77 |     inherited Destroy;
 | 
|---|
| 78 |   end;
 | 
|---|
| 79 | 
 | 
|---|
| 80 | 
 | 
|---|
| 81 |   FUNCTION TSerializableStringList.getCount : LongInt;
 | 
|---|
| 82 |   begin
 | 
|---|
| 83 |     result := stringList.count;
 | 
|---|
| 84 |   end;
 | 
|---|
| 85 | 
 | 
|---|
| 86 | 
 | 
|---|
| 87 |   PROCEDURE TSerializableStringList.add(const aString : String);
 | 
|---|
| 88 |   begin
 | 
|---|
| 89 |     stringList.add(aString);
 | 
|---|
| 90 |   end;
 | 
|---|
| 91 | 
 | 
|---|
| 92 |   FUNCTION TSerializableStringList.get(const anIndex : LongInt) : String;
 | 
|---|
| 93 |   begin
 | 
|---|
| 94 |     result := stringList[anIndex];
 | 
|---|
| 95 |   end;
 | 
|---|
| 96 | 
 | 
|---|
| 97 |   FUNCTION TSerializableStringList.getSerializedString : String;
 | 
|---|
| 98 |   Var
 | 
|---|
| 99 |     i : Integer;
 | 
|---|
| 100 |   begin
 | 
|---|
| 101 |     result := '';
 | 
|---|
| 102 |     for i := 0 To stringList.count-1 do
 | 
|---|
| 103 |     begin
 | 
|---|
| 104 |       if (i > 0) then result := result + '&';
 | 
|---|
| 105 |       result := result + StrEscapeAllCharsBy(stringList[i], ['&'], '\');
 | 
|---|
| 106 |     end;
 | 
|---|
| 107 |   end;
 | 
|---|
| 108 | 
 | 
|---|
| 109 | 
 | 
|---|
| 110 |   PROCEDURE TSerializableStringList.readValuesFromSerializedString(const aSerializedString : String);
 | 
|---|
| 111 |   Begin
 | 
|---|
| 112 |     if (length(aSerializedString) < 1) then exit;
 | 
|---|
| 113 | 
 | 
|---|
| 114 |     stringList.destroy;
 | 
|---|
| 115 |     stringList := TStringList.Create;
 | 
|---|
| 116 |     StrExtractStrings(stringList, aSerializedString, ['&'], '\');
 | 
|---|
| 117 |   end;
 | 
|---|
| 118 | 
 | 
|---|
| 119 | 
 | 
|---|
| 120 |   // ----------------------------------------------------------
 | 
|---|
| 121 | 
 | 
|---|
| 122 | 
 | 
|---|
| 123 |   Function StrEscapeAllCharsBy(Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char): String;
 | 
|---|
| 124 |   Var
 | 
|---|
| 125 |     i : Integer;
 | 
|---|
| 126 |     tmpChar : Char;
 | 
|---|
| 127 |   Begin
 | 
|---|
| 128 |     Result := '';
 | 
|---|
| 129 | 
 | 
|---|
| 130 |     for i := 1 To length(aReceiver) do
 | 
|---|
| 131 |     begin
 | 
|---|
| 132 |       tmpChar := aReceiver[i];
 | 
|---|
| 133 | 
 | 
|---|
| 134 |       if (tmpChar = anEscapeChar) or (tmpChar IN aSetOfChars) then
 | 
|---|
| 135 |         result := result + anEscapeChar + tmpChar
 | 
|---|
| 136 |       else
 | 
|---|
| 137 |         result := result + tmpChar;
 | 
|---|
| 138 |     end;
 | 
|---|
| 139 |   end;
 | 
|---|
| 140 | 
 | 
|---|
| 141 | 
 | 
|---|
| 142 |   Procedure StrExtractStrings(Var aResult: TStringList; Const aReceiver: String; const aSetOfChars: TSetOfChars; const anEscapeChar: char);
 | 
|---|
| 143 |   Var
 | 
|---|
| 144 |     i : Integer;
 | 
|---|
| 145 |     tmpChar,tmpNextChar : Char;
 | 
|---|
| 146 |     tmpPart: String;
 | 
|---|
| 147 |   Begin
 | 
|---|
| 148 |     if (length(aReceiver) < 1) then exit;
 | 
|---|
| 149 | 
 | 
|---|
| 150 |     tmpPart := '';
 | 
|---|
| 151 | 
 | 
|---|
| 152 |     i := 1;
 | 
|---|
| 153 |     while i <= length(aReceiver) do
 | 
|---|
| 154 |     begin
 | 
|---|
| 155 |       tmpChar := aReceiver[i];
 | 
|---|
| 156 |       if i < length(aReceiver) then
 | 
|---|
| 157 |         tmpNextChar := aReceiver[i+1]
 | 
|---|
| 158 |       else
 | 
|---|
| 159 |         tmpNextChar := #0;
 | 
|---|
| 160 | 
 | 
|---|
| 161 |       if (tmpChar = anEscapeChar) and (tmpNextChar = anEscapeChar) then
 | 
|---|
| 162 |       begin
 | 
|---|
| 163 |         tmpPart := tmpPart + anEscapeChar;
 | 
|---|
| 164 |         i := i + 2;
 | 
|---|
| 165 |       end
 | 
|---|
| 166 |       else
 | 
|---|
| 167 |         if (tmpChar = anEscapeChar) and (tmpNextChar IN aSetOfChars) then
 | 
|---|
| 168 |         begin
 | 
|---|
| 169 |           tmpPart := tmpPart + tmpNextChar;
 | 
|---|
| 170 |           i := i + 2;
 | 
|---|
| 171 |         end
 | 
|---|
| 172 |         else
 | 
|---|
| 173 |           if (tmpChar IN aSetOfChars) then
 | 
|---|
| 174 |           begin
 | 
|---|
| 175 |             aResult.add(tmpPart);
 | 
|---|
| 176 |             tmpPart := '';
 | 
|---|
| 177 |             i := i + 1;
 | 
|---|
| 178 |           end
 | 
|---|
| 179 |           else
 | 
|---|
| 180 |             begin
 | 
|---|
| 181 |             tmpPart := tmpPart + tmpChar;
 | 
|---|
| 182 |             i := i + 1;
 | 
|---|
| 183 |           end;
 | 
|---|
| 184 |     end;
 | 
|---|
| 185 |     aResult.add(tmpPart);
 | 
|---|
| 186 |   end;
 | 
|---|
| 187 | 
 | 
|---|
| 188 | 
 | 
|---|
| 189 |   Function StrTrimChars(const aReceiver: String; const aSetOfChars: TSetOfChars): String;
 | 
|---|
| 190 |   Var
 | 
|---|
| 191 |     i : Longint;
 | 
|---|
| 192 |     j : Longint;
 | 
|---|
| 193 |   Begin
 | 
|---|
| 194 |     i := 1;
 | 
|---|
| 195 |     while i < Length(aReceiver) do
 | 
|---|
| 196 |     begin
 | 
|---|
| 197 |       if aReceiver[i] in aSetOfChars then
 | 
|---|
| 198 |         inc(i)
 | 
|---|
| 199 |        else
 | 
|---|
| 200 |          break;
 | 
|---|
| 201 |     end;
 | 
|---|
| 202 | 
 | 
|---|
| 203 |     j := Length(aReceiver);
 | 
|---|
| 204 |     while j >= i do
 | 
|---|
| 205 |     begin
 | 
|---|
| 206 |       if aReceiver[j] in aSetOfChars then
 | 
|---|
| 207 |         dec(j)
 | 
|---|
| 208 |       else
 | 
|---|
| 209 |         break;
 | 
|---|
| 210 |     end;
 | 
|---|
| 211 | 
 | 
|---|
| 212 |     result := Copy(aReceiver, i, j-i+1);
 | 
|---|
| 213 |   end;
 | 
|---|
| 214 | 
 | 
|---|
| 215 | 
 | 
|---|
| 216 |   Function StrTrim(const aReceiver: String): String;
 | 
|---|
| 217 |   Begin
 | 
|---|
| 218 |     result := StrTrimChars(aReceiver, [' ']);
 | 
|---|
| 219 |   end;
 | 
|---|
| 220 | 
 | 
|---|
| 221 | 
 | 
|---|
| 222 |   Function StrEndsWith(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
| 223 |   Var
 | 
|---|
| 224 |     tmpStringPos : Longint;
 | 
|---|
| 225 |     tmpMatchPos : Longint;
 | 
|---|
| 226 |   Begin
 | 
|---|
| 227 |     tmpStringPos := length(aReceiver);
 | 
|---|
| 228 |     tmpMatchPos := length(anEndString);
 | 
|---|
| 229 | 
 | 
|---|
| 230 |     if tmpMatchPos > tmpStringPos then
 | 
|---|
| 231 |     begin
 | 
|---|
| 232 |       result := false;
 | 
|---|
| 233 |       exit;
 | 
|---|
| 234 |     end;
 | 
|---|
| 235 | 
 | 
|---|
| 236 |     while tmpMatchPos > 0 do
 | 
|---|
| 237 |     begin
 | 
|---|
| 238 |       if aReceiver[tmpStringPos] <> anEndString[tmpMatchPos] then
 | 
|---|
| 239 |       begin
 | 
|---|
| 240 |         result := false;
 | 
|---|
| 241 |         exit;
 | 
|---|
| 242 |       end;
 | 
|---|
| 243 |       dec(tmpMatchPos);
 | 
|---|
| 244 |       dec(tmpStringPos);
 | 
|---|
| 245 |     end;
 | 
|---|
| 246 | 
 | 
|---|
| 247 |     result := true;
 | 
|---|
| 248 |   end;
 | 
|---|
| 249 | 
 | 
|---|
| 250 | 
 | 
|---|
| 251 |   Function StrEndsWithIgnoringCase(const aReceiver: String; const anEndString: String): Boolean;
 | 
|---|
| 252 |   Var
 | 
|---|
| 253 |     tmpStringPos : Longint;
 | 
|---|
| 254 |     tmpMatchPos : Longint;
 | 
|---|
| 255 |   Begin
 | 
|---|
| 256 |     tmpStringPos := length(aString);
 | 
|---|
| 257 |     tmpMatchPos := length(anEndString);
 | 
|---|
| 258 | 
 | 
|---|
| 259 |     if tmpMatchPos > tmpStringPos then
 | 
|---|
| 260 |     begin
 | 
|---|
| 261 |       result := false;
 | 
|---|
| 262 |       exit;
 | 
|---|
| 263 |     end;
 | 
|---|
| 264 | 
 | 
|---|
| 265 |     while tmpMatchPos > 0 do
 | 
|---|
| 266 |     begin
 | 
|---|
| 267 |       if upcase(aString[tmpStringPos]) <> upcase(anEndString[tmpMatchPos]) then
 | 
|---|
| 268 |       begin
 | 
|---|
| 269 |         result := false;
 | 
|---|
| 270 |         exit;
 | 
|---|
| 271 |       end;
 | 
|---|
| 272 |       dec(tmpMatchPos);
 | 
|---|
| 273 |       dec(tmpStringPos);
 | 
|---|
| 274 |     end;
 | 
|---|
| 275 | 
 | 
|---|
| 276 |     result := true;
 | 
|---|
| 277 |   end;
 | 
|---|
| 278 | 
 | 
|---|
| 279 | END.
 | 
|---|