zeoslib  UNKNOWN
 All Files
ZMatchPattern.pas
Go to the documentation of this file.
1 {*********************************************************}
2 { }
3 { Zeos Database Objects }
4 { Regular Expressions }
5 { }
6 { Originally written by Sergey Seroukhov }
7 { }
8 {*********************************************************}
9 
10 {@********************************************************}
11 { Copyright (c) 1999-2012 Zeos Development Group }
12 { }
13 { License Agreement: }
14 { }
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. }
20 { }
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. }
39 { }
40 { }
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) }
45 { }
46 { http://www.sourceforge.net/projects/zeoslib. }
47 { }
48 { }
49 { Zeos Development Group. }
50 {********************************************************@}
51 
52 unit ZMatchPattern;
53 {
54  Author: Kevin Boylan
55  Ported By: Sergey Seroukhov
56 
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:
60 
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
65  [!abc] Ditto
66  [a-e] Matches a through e at that position
67 
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'
71 
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.
77 }
78 
79 {$I ZCore.inc}
80 
81 interface
82 
83 uses SysUtils;
84 
85 { Check if Text equal to pattern }
86 function IsMatch(const Pattern, Text: string): Boolean;
87 
88 implementation
89 
90 const
91 { Match defines }
92  MATCH_PATTERN = 6;
93  MATCH_LITERAL = 5;
94  MATCH_RANGE = 4;
95  MATCH_ABORT = 3;
96  MATCH_END = 2;
97  MATCH_VALID = 1;
98 { Pattern defines }
99 { PATTERN_VALID = 0;
100  PATTERN_ESC = -1;
101  PATTERN_RANGE = -2;
102  PATTERN_CLOSE = -3;
103  PATTERN_EMPTY = -4;
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 = '!';
112 
113 function Matche(Pattern, Text: string): Integer; forward;
114 function MatchAfterStar(Pattern, Text: string): Integer; forward;
115 //function IsPattern(Pattern: string): Boolean; forward;
116 
117 function IsMatch(const Pattern, Text: string): Boolean;
118 begin
119  Result := (Matche(Pattern, Text) = 1);
120 end;
121 
122 function Matche(Pattern, Text: string): Integer;
123 var
124  RangeStart, RangeEnd, P, T, PLen, TLen: Integer;
125  Invert, MemberMatch, Loop: Boolean;
126 begin
127  P := 1;
128  T := 1;
129  Pattern := AnsiLowerCase(pattern);
130  Text := AnsiLowerCase(Text);
131  PLen := Length(pattern);
132  TLen := Length(text);
133  Result := 0;
134  while ((Result = 0) and (P <= PLen)) do
135  begin
136  if T > TLen then
137  begin
138  if (Pattern[P] = MATCH_CHAR_KLEENE_CLOSURE) and (P+1 > PLen) then
139  Result := MATCH_VALID
140  else
141  Result := MATCH_ABORT;
142  Exit;
143  end
144  else
145  case (Pattern[P]) of
146  MATCH_CHAR_KLEENE_CLOSURE:
147  Result := MatchAfterStar(Copy(Pattern,P,PLen),Copy(Text,T,TLen));
148  MATCH_CHAR_RANGE_OPEN:
149  begin
150  Inc(P);
151  Invert := False;
152  if (Pattern[P] = MATCH_CHAR_EXCLAMATION_NEGATE) or
153  (Pattern[P] = MATCH_CHAR_CARET_NEGATE) then
154  begin
155  Invert := True;
156  Inc(P);
157  end;
158  if (Pattern[P] = MATCH_CHAR_RANGE_CLOSE) then
159  begin
160  Result := MATCH_PATTERN;
161  Exit;
162  end;
163  MemberMatch := False;
164  Loop := True;
165  while (Loop and (Pattern[P] <> MATCH_CHAR_RANGE_CLOSE)) do
166  begin
167  RangeStart := P;
168  RangeEnd := P;
169  Inc(P);
170  if P > PLen then
171  begin
172  Result := MATCH_PATTERN;
173  Exit;
174  end;
175  if Pattern[P] = MATCH_CHAR_RANGE then
176  begin
177  Inc(P);
178  RangeEnd := P;
179  if (P > PLen) or (Pattern[RangeEnd] = MATCH_CHAR_RANGE_CLOSE) then
180  begin
181  Result := MATCH_PATTERN;
182  Exit;
183  end;
184  Inc(P);
185  end;
186  if P > PLen then
187  begin
188  Result := MATCH_PATTERN;
189  Exit;
190  end;
191  if RangeStart < RangeEnd then
192  begin
193  if (Text[T] >= Pattern[RangeStart]) and
194  (Text[T] <= Pattern[RangeEnd]) then
195  begin
196  MemberMatch := True;
197  Loop := False;
198  end;
199  end
200  else
201  begin
202  if (Text[T] >= Pattern[RangeEnd]) and
203  (Text[T] <= Pattern[RangeStart]) then
204  begin
205  MemberMatch := True;
206  Loop := False;
207  end;
208  end;
209  end;
210  if (Invert and MemberMatch) or (not (Invert or MemberMatch)) then
211  begin
212  Result := MATCH_RANGE;
213  Exit;
214  end;
215  if MemberMatch then
216  while (P <= PLen) and (Pattern[P] <> MATCH_CHAR_RANGE_CLOSE) do
217  Inc(P);
218  if P > PLen then
219  begin
220  Result := MATCH_PATTERN;
221  Exit;
222  end;
223  end;
224  else
225  if Pattern[P] <> MATCH_CHAR_SINGLE then
226  if Pattern[P] <> Text[T] then
227  Result := MATCH_LITERAL;
228  end;
229  Inc(P);
230  Inc(T);
231  end;
232  if Result = 0 then
233  if T <= TLen then
234  Result := MATCH_END
235  else
236  Result := MATCH_VALID;
237 end;
238 
239 function MatchAfterStar(Pattern, Text: string): Integer;
240 var
241  P, T, PLen, TLen: Integer;
242 begin
243  Result := 0;
244  P := 1;
245  T := 1;
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'
249  begin
250  Result := MATCH_VALID;
251  Exit;
252  end;
253  if (PLen = 0) or (TLen = 0) then
254  begin
255  Result := MATCH_ABORT;
256  Exit;
257  end;
258  while ((T <= TLen) and (P < PLen)) and ((Pattern[P] = MATCH_CHAR_SINGLE) or
259  (Pattern[P] = MATCH_CHAR_KLEENE_CLOSURE)) do
260  begin
261  if Pattern[P] = MATCH_CHAR_SINGLE then
262  Inc(T);
263  Inc(P);
264  end;
265  if T >= TLen then
266  begin
267  Result := MATCH_ABORT;
268  Exit;
269  end;
270  if P >= PLen then
271  begin
272  Result := MATCH_VALID;
273  Exit;
274  end;
275  repeat
276  if (Pattern[P] = Text[T]) or (Pattern[P] = MATCH_CHAR_RANGE_OPEN) then
277  begin
278  Pattern := Copy(Pattern, P, PLen);
279  Text := Copy(Text, T, TLen);
280  PLen := Length(Pattern);
281  TLen := Length(Text);
282  p := 1;
283  t := 1;
284  Result := Matche(Pattern, Text);
285  if Result <> MATCH_VALID then
286  Result := 0;//retry until end of Text, (check below) or Result valid
287  end;
288  Inc(T);
289  if (T > TLen) or (P > PLen) then
290  begin
291  Result := MATCH_ABORT;
292  Exit;
293  end;
294  until Result <> 0;
295 end;
296 
297 (*
298 function IsPattern(const Pattern: string): Boolean;
299 var
300  I: Integer;
301 begin
302  Result := False;
303  for I := 1 to Length(Pattern) do
304  if Pos(Pattern[I], '[]?*') > 0 then
305  begin
306  Result := True;
307  Exit;
308  end;
309 end;
310 *)
311 
312 end.
313 
314