-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathregexp.go
71 lines (63 loc) · 1.52 KB
/
regexp.go
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
// Package regexp is a basic regexp library.
//
// The library was implemented to explore regexp parsing and NFA representation.
package regexp
// Regexp is a compiled regular expression.
type Regexp struct {
start, term node
pattern string
}
// Compile compiles a pattern into Regexp.
func Compile(pattern string) (r *Regexp, err error) {
r = &Regexp{pattern: pattern}
if r.start, r.term, err = parse(pattern); err != nil {
return nil, err
}
return
}
// MustCompile invokes Compile and panics if an error is returned.
func MustCompile(pattern string) *Regexp {
r, err := Compile(pattern)
if err != nil {
panic(err)
}
return r
}
// MatchString returns true if the the passed input matches the pattern.
func (r *Regexp) MatchString(input string) bool {
cur, next := nodeSet{}, nodeSet{}
cur.add(r.start)
for _, r := range input {
for n := range cur {
if m, ok := n.(matchNode); ok && m.matches(r) {
next.add(m.next())
}
}
if len(next) == 0 {
return false
}
cur.clear()
cur, next = next, cur
}
_, hasTerminal := cur[r.term]
return hasTerminal
}
////////////////////////////////////////////////////////////////////////////////
// nodeSet
////////////////////////////////////////////////////////////////////////////////
// nodeSet is used to evaluate the NFA
type nodeSet map[node]struct{}
func (s nodeSet) add(n node) {
if _, exists := s[n]; exists {
return
}
s[n] = struct{}{}
for _, e := range n.epsilons() {
s.add(e)
}
}
func (s nodeSet) clear() {
for n := range s {
delete(s, n)
}
}