File: match.g

package info (click to toggle)
gap-browse 1.8.21%2Bdfsg-1
  • links: PTS
  • area: main
  • in suites: forky, sid, trixie
  • size: 8,296 kB
  • sloc: xml: 1,961; ansic: 1,342; makefile: 163; javascript: 155; sh: 20
file content (101 lines) | stat: -rw-r--r-- 2,627 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

# admit wildcards for all group names in the interface functions!
# (means that each such pattern will be replaced by the list of all
# group names that match, and then `DuplicateFreeList' is called;
# problem: when alternative names are supported then do we have to replace
# them by standard names, in order to get no *group* twice?

#T case sensitive/insensitive search?
IsMatchingString:= function( string, pattern )
local one, any, clean, addany, i, s, p, pp, pp2, pos;

one:= '?';
any:= '*';

# Normalize the pattern: ** -> *, *? -> ?*
# (So a * must be followed by a proper character!)
clean:= "";
addany:= false;
i:= 1;
while i <= Length( pattern ) do
  if pattern[i] = any then
    if i < Length( pattern ) then
      if   pattern[ i+1 ] = one then
        addany:= true;
        Add( clean, one );
        i:= i+1;
      elif pattern[ i+1 ] <> any then
        Add( clean, any );
      fi;
      i:= i+1;
    else
      Add( clean, any );
      i:= i+1;
    fi;
  else
    if addany then
      addany:= false;
      Add( clean, any );
    fi;
    Add( clean, pattern[i] );
    i:= i+1;
  fi;
od;
if addany then
  Add( clean, any );
fi;
pattern:= clean;

s:= 1;
p:= 1;
while p <= Length( pattern ) do
  if pattern[p] = one then
    # Any character matches.
    if s > Length( string ) then
      return false;
    fi;
    p:= p + 1;
    s:= s + 1;
  elif pattern[p] = any then
    # An arbitrary substring matches.
    if p = Length( pattern ) then
      return true;
    fi;
    # There is at least one explicit string in the pattern.
    pp:= p+1;
    pp2:= pp+1;
    while pp2 <= Length( pattern ) and not pattern[ pp2 ] in [ one, any ] do
      pp2:= pp2+1;
    od;
    # now the segment is in pp .. pp2-1
    pos:= PositionSublist( string, pattern{ [ pp ..pp2-1 ] }, s-1 );
    while pos <> fail do
      if IsMatchingString( string{ [ pos .. Length( string ) ] },
                           pattern{ [ pp .. Length( pattern ) ] } ) then
        return true;
      fi;
      pos:= PositionSublist( string, pattern{ [ pp ..pp2-1 ] }, pos );
    od;
    return false;
  else
    # The current characters must coincide if there is a matching.
    if s > Length( string ) or string[ s ] <> pattern[ p ] then
      return false;
    fi;
    p:= p + 1;
    s:= s + 1;
  fi;
od;

return s > Length( string );
end;;


test:= function()
  return ForAll( [ "M12", "*M12", "M12*", "*M12*", "M1*2",
                   "M1?", "?12", "M?2" ],
                 pattern -> IsMatchingString( "M12", pattern ) ) and
         ForAll( [ "?M12", "M12?" ],
                 pattern -> not IsMatchingString( "M12", pattern ) );
end;;