21 character,
save :: c_escape =
'#' 22 integer,
parameter :: sym_eol = -128
23 integer,
parameter :: sym_anychar = 500
24 integer,
parameter :: sym_question = 501
25 integer,
parameter :: sym_plus = 502
26 integer,
parameter :: sym_star = 503
27 integer,
parameter :: sym_normal_set = 520
28 integer,
parameter :: sym_reversed_set = 521
29 integer,
parameter :: sym_headfix = 540
30 integer,
parameter :: sym_tailfix = 541
31 integer,
parameter :: sym_isdigit = 560
32 integer,
parameter :: sym_isalpha = 561
33 integer,
parameter :: sym_isword = 562
34 integer,
parameter :: sym_isspace = 563
35 integer,
parameter :: sym_isxdigit = 564
36 integer,
parameter :: sym_count_base = 1000
40 subroutine preprocess_pattern(pattern, symbols)
44 character(len = *),
intent(in):: pattern
45 integer,
intent(out):: symbols(:)
46 integer:: i, j, code, imax, j_last_set
47 integer:: status, stat_return
48 integer,
parameter:: stat_init = 1, stat_escape = 2, &
49 stat_open_set = 3, stat_in_set = 4, stat_hexadecimal = 5
53 stat_return = stat_init
56 imax = len_trim(pattern)
62 if (c == c_escape)
then 65 else if (c ==
"[")
then 66 symbols(j) = sym_normal_set
67 status = stat_open_set
68 else if (c ==
".")
then 69 symbols(j) = sym_anychar
70 else if (c ==
"?")
then 71 symbols(j) = sym_question
72 else if (c ==
"+")
then 74 else if (c ==
"*")
then 76 else if (c ==
"^" .and. i == 1)
then 77 symbols(j) = sym_headfix
78 else if (c ==
"$" .and. i == imax)
then 79 symbols(j) = sym_tailfix
84 if (c ==
'd' .or. c ==
'D')
then 85 symbols(j) = sym_isdigit
86 else if (c ==
'a' .or. c ==
'A')
then 87 symbols(j) = sym_isalpha
88 else if (c ==
'w' .or. c ==
'W')
then 89 symbols(j) = sym_isword
90 else if (c ==
's' .or. c ==
'S')
then 91 symbols(j) = sym_isspace
92 else if (c ==
'z' .or. c ==
'Z')
then 93 symbols(j) = sym_isxdigit
94 else if (c ==
'x' .or. c ==
'X')
then 96 status = stat_hexadecimal
102 case(stat_hexadecimal)
103 code = index(
"123456789ABCDEFabcdef", c)
104 if (code >= 16) code = code - 6
105 if (symbols(j) == -1)
then 109 symbols(j) = symbols(j) * 16 + code
113 symbols(j) = sym_count_base
115 stat_return = stat_in_set
117 symbols(j - 1) = sym_reversed_set
119 else if (c == c_escape)
then 123 symbols(j) = ichar(c)
128 symbols(j_last_set) = sym_count_base + j - j_last_set - 1
129 stat_return = stat_init
132 else if (c == c_escape)
then 136 symbols(j) = ichar(c)
143 symbols(j) = ichar(
' ')
145 symbols(j) = sym_count_base
147 symbols(j_last_set) = sym_count_base + j - j_last_set - 1
149 end subroutine preprocess_pattern
153 recursive subroutine match_here(ipat, text, length)
154 integer,
intent(in):: ipat(:)
155 character(len = *),
intent(in):: text
156 integer,
intent(out):: length
157 integer:: s1, s2, remain, i, hitmax, hitcount, hit_at_least
161 if (
size(ipat) == 0 .or. ipat(1) == sym_eol)
then 166 if (ipat(1) == sym_tailfix)
then 174 if (len(text) == 0)
then 179 if (ipat(1) == sym_normal_set)
then 181 s2 = 2 + ipat(2) - sym_count_base
183 else if (ipat(1) == sym_reversed_set)
then 185 s2 = 2 + ipat(2) - sym_count_base
194 select case (ipat(s2 + 1))
212 if (hit(ipat(s1:s2), text(i:i)) .neqv. normal_hit)
then 218 if (hitcount < hit_at_least)
then 224 do, i = 1 + hitcount, 1 + hit_at_least, -1
225 call match_here(ipat(remain: ), text(i: ), length)
226 if (length >= 0)
then 227 length = length + i - 1
232 end subroutine match_here
234 logical function hit(ipat, c)
result(result)
235 integer,
intent(in):: ipat(:)
236 character(len=*),
intent(in):: c
237 character(len=*),
parameter:: &
238 & DIGIT =
"0123456789", &
239 & XDIGIT =
"ABCDEFabcdef", &
240 & ALPHA =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 243 do, i = 1,
size(ipat)
248 result = (index(alpha, c) > 0)
250 result = (index(digit, c) > 0)
252 result = (index(digit, c) > 0 .or. index(alpha, c) > 0 .or. &
255 result = (index(digit, c) > 0 .or. index(xdigit, c) > 0)
257 result = (c ==
' ' .or. (iachar(c) >= 8 .and. iachar(c) <= 13))
259 result = (ipat(i) == ichar(c))
266 subroutine match(pattern, text, start, length)
321 character(len = *),
intent(in):: pattern, text
322 integer,
intent(out):: start, length
323 integer,
allocatable:: ipattern(:)
324 integer:: text_length
327 if (len(pattern) <= 0)
then 333 allocate(ipattern(len(pattern) + 2))
334 call preprocess_pattern(pattern, ipattern)
336 if (ipattern(1) == sym_headfix)
then 338 call match_here(ipattern(2: ), text, length)
339 if (length < 0)
goto 995
343 text_length = len(text)
344 do, start = 1, text_length + 1
345 call match_here(ipattern, text(start:text_length), length)
346 if (length >= 0)
goto 999
Provide simple regular expression subroutine: 'match'.
subroutine, public match(pattern, text, start, length)