1 {*********************************************************}
3 { Zeos Database Objects }
4 { Regular Expressions }
6 { Originally written by Sergey Seroukhov }
8 {*********************************************************}
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
13 { License Agreement: }
15 { This library is distributed in the hope that it will be }
16 { useful, but WITHOUT ANY WARRANTY; without even the }
17 { implied warranty of MERCHANTABILITY or FITNESS FOR }
18 { A PARTICULAR PURPOSE. See the GNU Lesser General }
19 { Public License for more details. }
21 { The source code of the ZEOS Libraries and packages are }
22 { distributed under the Library GNU General Public }
23 { License (see the file COPYING / COPYING.ZEOS) }
24 { with the following modification: }
25 { As a special exception, the copyright holders of this }
26 { library give you permission to link this library with }
27 { independent modules to produce an executable, }
28 { regardless of the license terms of these independent }
29 { modules, and to copy and distribute the resulting }
30 { executable under terms of your choice, provided that }
31 { you also meet, for each linked independent module, }
32 { the terms and conditions of the license of that module. }
33 { An independent module is a module which is not derived }
34 { from or based on this library. If you modify this }
35 { library, you may extend this exception to your version }
36 { of the library, but you are not obligated to do so. }
37 { If you do not wish to do so, delete this exception }
38 { statement from your version. }
41 { The project web site is located on: }
42 { http://zeos.firmos.at (FORUM) }
43 { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)}
44 { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) }
46 { http://www.sourceforge.net/projects/zeoslib. }
49 { Zeos Development Group. }
50 {********************************************************@}
55 Ported By: Sergey Seroukhov
57 This code is meant to allow wildcard pattern matches.
58 It is VERY useful for matching filename wildcard patterns.
59 It allows unix grep-like pattern comparisons, for instance:
61 ? Matches any single characer
62 * Matches any contiguous characters
63 [abc] Matches a or b or c at that position
64 [^abc] Matches anything but a or b or c at that position
66 [a-e] Matches a through e at that position
68 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc
69 'this [e-n]s a [!zy]est' - Would match 'this is a test',
70 but would not match 'this as a yest'
72 This is a Delphi VCL translation from C code that was downloaded from CIS.
73 C code was written by J. Kerceval and released to public domain 02/20/1991.
74 This code is ofcourse also public domain. I would appreciate it if you would
75 let me know if you find any bugs. I would also appreciate any notes sent my
76 way letting me know if you find it useful.
85 { Check if Text equal to pattern }
86 function IsMatch(const Pattern, Text: string): Boolean;
104 }{ Character defines }
105 MATCH_CHAR_SINGLE = '?';
106 MATCH_CHAR_KLEENE_CLOSURE = '*';
107 MATCH_CHAR_RANGE_OPEN = '[';
108 MATCH_CHAR_RANGE = '-';
109 MATCH_CHAR_RANGE_CLOSE = ']';
110 MATCH_CHAR_CARET_NEGATE = '^';
111 MATCH_CHAR_EXCLAMATION_NEGATE = '!';
113 function Matche(Pattern, Text: string): Integer; forward;
114 function MatchAfterStar(Pattern, Text: string): Integer; forward;
115 //function IsPattern(Pattern: string): Boolean; forward;
117 function IsMatch(const Pattern, Text: string): Boolean;
119 Result := (Matche(Pattern, Text) = 1);
122 function Matche(Pattern, Text: string): Integer;
124 RangeStart, RangeEnd, P, T, PLen, TLen: Integer;
125 Invert, MemberMatch, Loop: Boolean;
129 Pattern := AnsiLowerCase(pattern);
130 Text := AnsiLowerCase(Text);
131 PLen := Length(pattern);
132 TLen := Length(text);
134 while ((Result = 0) and (P <= PLen)) do
138 if (Pattern[P] = MATCH_CHAR_KLEENE_CLOSURE) and (P+1 > PLen) then
139 Result := MATCH_VALID
141 Result := MATCH_ABORT;
146 MATCH_CHAR_KLEENE_CLOSURE:
147 Result := MatchAfterStar(Copy(Pattern,P,PLen),Copy(Text,T,TLen));
148 MATCH_CHAR_RANGE_OPEN:
152 if (Pattern[P] = MATCH_CHAR_EXCLAMATION_NEGATE) or
153 (Pattern[P] = MATCH_CHAR_CARET_NEGATE) then
158 if (Pattern[P] = MATCH_CHAR_RANGE_CLOSE) then
160 Result := MATCH_PATTERN;
163 MemberMatch := False;
165 while (Loop and (Pattern[P] <> MATCH_CHAR_RANGE_CLOSE)) do
172 Result := MATCH_PATTERN;
175 if Pattern[P] = MATCH_CHAR_RANGE then
179 if (P > PLen) or (Pattern[RangeEnd] = MATCH_CHAR_RANGE_CLOSE) then
181 Result := MATCH_PATTERN;
188 Result := MATCH_PATTERN;
191 if RangeStart < RangeEnd then
193 if (Text[T] >= Pattern[RangeStart]) and
194 (Text[T] <= Pattern[RangeEnd]) then
202 if (Text[T] >= Pattern[RangeEnd]) and
203 (Text[T] <= Pattern[RangeStart]) then
210 if (Invert and MemberMatch) or (not (Invert or MemberMatch)) then
212 Result := MATCH_RANGE;
216 while (P <= PLen) and (Pattern[P] <> MATCH_CHAR_RANGE_CLOSE) do
220 Result := MATCH_PATTERN;
225 if Pattern[P] <> MATCH_CHAR_SINGLE then
226 if Pattern[P] <> Text[T] then
227 Result := MATCH_LITERAL;
236 Result := MATCH_VALID;
239 function MatchAfterStar(Pattern, Text: string): Integer;
241 P, T, PLen, TLen: Integer;
246 PLen := Length(Pattern);
247 TLen := Length(Text);
248 if (TLen = 1) and (PLen = 1) then //pattern like '*ring*' schould not match if Text 'A'
250 Result := MATCH_VALID;
253 if (PLen = 0) or (TLen = 0) then
255 Result := MATCH_ABORT;
258 while ((T <= TLen) and (P < PLen)) and ((Pattern[P] = MATCH_CHAR_SINGLE) or
259 (Pattern[P] = MATCH_CHAR_KLEENE_CLOSURE)) do
261 if Pattern[P] = MATCH_CHAR_SINGLE then
267 Result := MATCH_ABORT;
272 Result := MATCH_VALID;
276 if (Pattern[P] = Text[T]) or (Pattern[P] = MATCH_CHAR_RANGE_OPEN) then
278 Pattern := Copy(Pattern, P, PLen);
279 Text := Copy(Text, T, TLen);
280 PLen := Length(Pattern);
281 TLen := Length(Text);
284 Result := Matche(Pattern, Text);
285 if Result <> MATCH_VALID then
286 Result := 0;//retry until end of Text, (check below) or Result valid
289 if (T > TLen) or (P > PLen) then
291 Result := MATCH_ABORT;
298 function IsPattern(const Pattern: string): Boolean;
303 for I := 1 to Length(Pattern) do
304 if Pos(Pattern[I], '[]?*') > 0 then