-
-
Notifications
You must be signed in to change notification settings - Fork 8
/
count.go
104 lines (82 loc) · 2.32 KB
/
count.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
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
102
103
104
package genex
import (
"math"
"regexp/syntax"
)
// Count computes the total number of matches the `input` regex would generate after whitelisting `charset`.
// The `infinite` argument caps the maximum boundary of repetition operators.
func Count(input, charset *syntax.Regexp, infinite int) float64 {
var count func(input, charset *syntax.Regexp, infinite int) float64
count = func(input, charset *syntax.Regexp, infinite int) float64 {
result := float64(0)
switch input.Op {
case syntax.OpStar, syntax.OpPlus, syntax.OpQuest, syntax.OpRepeat:
value := float64(1)
for _, sub := range input.Sub {
value *= count(sub, charset, infinite)
}
switch input.Op {
case syntax.OpStar:
input.Min = 0
input.Max = -1
case syntax.OpPlus:
input.Min = 1
input.Max = -1
case syntax.OpQuest:
input.Min = 0
input.Max = 1
}
if input.Max == -1 && infinite >= 0 {
input.Max = input.Min + infinite
}
if input.Max == -1 {
result = math.Inf(1)
} else if value > 1 {
if input.Min == input.Max {
result = math.Pow(value, float64(input.Min))
} else {
result = (math.Pow(value, float64(input.Max)+1) - 1) / (value - 1)
if input.Min > 0 {
result -= (math.Pow(value, float64(input.Min)+0) - 1) / (value - 1)
}
}
} else {
result = float64(input.Max-input.Min) + 1
}
case syntax.OpCharClass, syntax.OpAnyCharNotNL, syntax.OpAnyChar:
if input.Op != syntax.OpCharClass {
input = charset
}
for i := 0; i < len(input.Rune); i += 2 {
for j := 0; j < len(charset.Rune); j += 2 {
bounds := []float64{
math.Max(float64(input.Rune[i]), float64(charset.Rune[j])),
math.Min(float64(input.Rune[i+1]), float64(charset.Rune[j+1])),
}
if bounds[0] <= bounds[1] {
result += bounds[1] - bounds[0] + 1
}
}
}
case syntax.OpCapture, syntax.OpConcat:
result = 1
for _, sub := range input.Sub {
result *= count(sub, charset, infinite)
}
case syntax.OpAlternate:
for _, sub := range input.Sub {
result += count(sub, charset, infinite)
}
default:
result = 1
}
if math.IsNaN(result) {
result = math.Inf(1)
}
return math.Max(1, result)
}
if charset.Op != syntax.OpCharClass {
charset, _ = syntax.Parse(`[[:print:]]`, syntax.Perl)
}
return count(input, charset, infinite)
}