COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/wildcard.e3475.00%535891.38%5
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
new()020.00%2
is_match()323396.97%1
qmatch()141593.33%1
wildcard_file()6785.71%1
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
-- wildcard.e
3
namespace wildcard
4
5
--****
6
-- == Wildcard Matching
7
--
8
-- <>
9
--
10
11
--****
12
-- === Routines
13
14
include std/text.e as txt -- upper/lower
15
16
17
18
--**
19
-- Return a text pattern
20
--
21
-- Parameters:
22
-- # ##pattern## : a sequence representing a text string pattern
23
--
24
-- Returns:
25
-- A the same ##pattern##.
26
--
27
-- Comments:
28
-- You might wonder why this function even exists. If you use it and ##is_match## you can easily
29
-- change to the routines found in std/regex.e. And if using std/regex.e and you restrict
30
-- yourself to only using
31
-- [[:regex:new]] and [[:regex:is_match]], you can change to using
32
-- std/wildcards.e with very little modification to your source code.
33
--
34
-- Suppose you work for a hotel and you set up a system for looking up
35
-- guests.
36
--
37
--
38
-- -- The user can use regular expressions to find guests at a hotel...
39
-- include std/regex.e as uip -- user input patterns 'uip'
40
-- puts(1,"Enter a person to find. You may use regular expressions:")
41
--
42
-- sequence person_to_find
43
-- object pattern
44
-- person_to_find = gets(0)
45
-- person_to_find_pattern = uip:new(person_to_find[1..$-1])
46
-- while sequence(line) do
47
-- line = line[1..$-1]
48
-- if uip:is_match(person_to_find_pattern, line) then
49
-- -- code for telling users the person is there.
50
-- end if
51
-- -- code loads next name into 'line'
52
-- end while
53
-- close(dbfd)
54
--
55
--
56
-- Later the hotel manager tells you that the users would rather use wildcard
57
-- matching you need only change the include line and the prompt for the pattern.
58
--
59
-- -- This will make things simpler...
60
-- include std/wildcard.e as uip -- user input patterns 'uip'.
61
-- puts(1,"Enter a person to find. You may use '*' and '?' wildcards:")
62
--
63
--
64
-- See Also: [[:is_match]]
650
660
return s
67
end function
68
69249
70
-- find pattern p in string s
71
-- p may have '?' wild cards (but not '*')
72
integer k
73
74249
if not find('?', p) then
75248
return match(p, s) -- fast
76
end if
77
-- must allow for '?' wildcard
781
for i = 1 to length(s) - length(p) + 1 do
794
k = i
804
for j = 1 to length(p) do
818
if p[j] != s[k] and p[j] != '?' then
823
k = 0
833
exit
84
end if
855
k += 1
865
end for
874
if k != 0 then
881
return i
89
end if
903
end for
910
return 0
92
end function
93
94101
constant END_MARKER = -1
95
96
--**
97
-- Determine whether a string matches a pattern. The pattern may contain * and ? wildcards.
98
--
99
-- Parameters:
100
-- # ##pattern## : a string, the pattern to match
101
-- # ##string## : the string to be matched against
102
--
103
-- Returns:
104
-- An **integer**, TRUE if ##string## matches ##pattern##, else FALSE.
105
--
106
-- Comments:
107
--
108
-- Character comparisons are case sensitive.
109
-- If you want case insensitive comparisons, pass both ##pattern## and ##string## through [[:upper]](), or both through [[:lower]](), before calling ##is_match##().
110
--
111
-- If you want to detect a pattern anywhere within a string, add * to each end of the pattern:
112
-- {{{
113
-- i = is_match('*' & pattern & '*', string)
114
-- }}}
115
--
116
-- There is currently no way to treat * or ? literally in a pattern.
117
--
118
-- Example 1:
119
--
120
-- i = is_match("A?B*", "AQBXXYY")
121
-- -- i is 1 (TRUE)
122
--
123
--
124
-- Example 2:
125
--
126
-- i = is_match("*xyz*", "AAAbbbxyz")
127
-- -- i is 1 (TRUE)
128
--
129
--
130
-- Example 3:
131
--
132
-- i = is_match("A*B*C", "a111b222c")
133
-- -- i is 0 (FALSE) because upper/lower case doesn't match
134
--
135
--
136
-- Example 4:
137
-- ##bin/search.ex##
138
--
139
-- See Also:
140
-- [[:wildcard_file]], [[:upper]], [[:lower]], [[:Regular Expressions]]
141
142257
143
integer p, f, t
144
sequence match_string
145
146257
pattern = pattern & END_MARKER
147257
string = string & END_MARKER
148257
p = 1
149257
f = 1
150257
while f <= length(string) do
151522
if not find(pattern[p], {string[f], '?'}) then
152496
if pattern[p] = '*' then
153489
while pattern[p] = '*' do
154489
p += 1
155489
end while
156489
if pattern[p] = END_MARKER then
157240
return 1
158
end if
159249
match_string = ""
160249
while pattern[p] != '*' do
161271
match_string = match_string & pattern[p]
162271
if pattern[p] = END_MARKER then
16310
exit
164
end if
165261
p += 1
166261
end while
167249
if pattern[p] = '*' then
168239
p -= 1
169
end if
170249
t = qmatch(match_string, string[f..$])
171249
if t = 0 then
1726
return 0
173
else
174243
f += t + length(match_string) - 2
175
end if
176
else
1777
return 0
178
end if
179
end if
180269
p += 1
181269
f += 1
182269
if p > length(pattern) then
1834
return f > length(string)
184
end if
185265
end while
1860
return 0
187
end function
188
189
--**
190
-- Determine whether a file name matches a wildcard pattern.
191
--
192
-- Parameters:
193
-- # ##pattern## : a string, the pattern to match
194
-- # ##filename## : the string to be matched against
195
--
196
-- Returns:
197
-- An **integer**, TRUE if ##filename## matches ##pattern##, else FALSE.
198
--
199
-- Comments:
200
--
201
-- ~* matches any 0 or more characters, ? matches any single character. On //Unix// the
202
-- character comparisons are case sensitive. On Windows they are not.
203
--
204
-- You might use this function to check the output of the [[:dir]]() routine for file names that match a pattern supplied by the user of your program.
205
--
206
-- Example 1:
207
--
208
-- i = wildcard_file("AB*CD.?", "aB123cD.e")
209
-- -- i is set to 1 on Windows, 0 on Linux or FreeBSD
210
--
211
--
212
-- Example 2:
213
--
214
-- i = wildcard_file("AB*CD.?", "abcd.ex")
215
-- -- i is set to 0 on all systems,
216
-- -- because the file type has 2 letters not 1
217
--
218
--
219
-- Example 3:
220
-- ##bin/search.ex##
221
--
222
-- See Also:
223
-- [[:is_match]], [[:dir]]
224
225254
226254
ifdef not UNIX then
227
pattern = txt:upper(pattern)
228
filename = txt:upper(filename)
229
end ifdef
230
231254
if not find('.', pattern) then
2320
pattern = pattern & '.'
233
end if
234
235254
if not find('.', filename) then
2365
filename = filename & '.'
237
end if
238
239254
return is_match(pattern, filename)
240
end function