136 lines
2.9 KiB
Go
136 lines
2.9 KiB
Go
|
// Licensed to Elasticsearch B.V. under one or more contributor
|
||
|
// license agreements. See the NOTICE file distributed with
|
||
|
// this work for additional information regarding copyright
|
||
|
// ownership. Elasticsearch B.V. licenses this file to you under
|
||
|
// the Apache License, Version 2.0 (the "License"); you may
|
||
|
// not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing,
|
||
|
// software distributed under the License is distributed on an
|
||
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||
|
// KIND, either express or implied. See the License for the
|
||
|
// specific language governing permissions and limitations
|
||
|
// under the License.
|
||
|
|
||
|
package match
|
||
|
|
||
|
import (
|
||
|
"regexp"
|
||
|
"regexp/syntax"
|
||
|
)
|
||
|
|
||
|
func compile(r *syntax.Regexp) (stringMatcher, error) {
|
||
|
switch {
|
||
|
case r.Op == syntax.OpLiteral:
|
||
|
s := string(r.Rune)
|
||
|
return &substringMatcher{s, []byte(s)}, nil
|
||
|
|
||
|
case isExactLiteral(r):
|
||
|
s := string(r.Sub[1].Rune)
|
||
|
return &equalsMatcher{s, []byte(s)}, nil
|
||
|
|
||
|
case isAltLiterals(r):
|
||
|
var literals [][]byte
|
||
|
for _, sub := range r.Sub {
|
||
|
literals = append(literals, []byte(string(sub.Rune)))
|
||
|
}
|
||
|
return &altSubstringMatcher{literals}, nil
|
||
|
|
||
|
case isOneOfLiterals(r):
|
||
|
var literals [][]byte
|
||
|
for _, sub := range r.Sub[1].Sub {
|
||
|
literals = append(literals, []byte(string(sub.Rune)))
|
||
|
}
|
||
|
return &oneOfMatcher{literals}, nil
|
||
|
|
||
|
case isPrefixLiteral(r):
|
||
|
s := []byte(string(r.Sub[1].Rune))
|
||
|
return &prefixMatcher{s}, nil
|
||
|
|
||
|
case isPrefixAltLiterals(r):
|
||
|
var literals [][]byte
|
||
|
for _, sub := range r.Sub[1].Sub {
|
||
|
literals = append(literals, []byte(string(sub.Rune)))
|
||
|
}
|
||
|
return &altPrefixMatcher{literals}, nil
|
||
|
|
||
|
case isPrefixNumDate(r):
|
||
|
return compilePrefixNumDate(r)
|
||
|
|
||
|
case isEmptyText(r):
|
||
|
var m *emptyStringMatcher
|
||
|
return m, nil
|
||
|
|
||
|
case isEmptyTextWithWhitespace(r):
|
||
|
var m *emptyWhiteStringMatcher
|
||
|
return m, nil
|
||
|
|
||
|
case isAnyMatch(r):
|
||
|
var m *matchAny
|
||
|
return m, nil
|
||
|
|
||
|
default:
|
||
|
|
||
|
r, err := regexp.Compile(r.String())
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return r, nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func compilePrefixNumDate(r *syntax.Regexp) (stringMatcher, error) {
|
||
|
m := &prefixNumDate{}
|
||
|
|
||
|
i := 1
|
||
|
if r.Sub[i].Op == syntax.OpLiteral {
|
||
|
m.prefix = []byte(string(r.Sub[i].Rune))
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
digitLen := func(r *syntax.Regexp) int {
|
||
|
if r.Op == syntax.OpConcat {
|
||
|
return len(r.Sub)
|
||
|
}
|
||
|
return 1
|
||
|
}
|
||
|
|
||
|
var digits []int
|
||
|
var seps [][]byte
|
||
|
|
||
|
digits = append(digits, digitLen(r.Sub[i]))
|
||
|
i++
|
||
|
|
||
|
for i < len(r.Sub) {
|
||
|
lit := []byte(string(r.Sub[i].Rune))
|
||
|
i++
|
||
|
|
||
|
// capture literal suffix
|
||
|
if i == len(r.Sub) {
|
||
|
m.suffix = lit
|
||
|
break
|
||
|
}
|
||
|
|
||
|
seps = append(seps, lit)
|
||
|
digits = append(digits, digitLen(r.Sub[i]))
|
||
|
i++
|
||
|
}
|
||
|
|
||
|
minLen := len(m.prefix) + len(m.suffix)
|
||
|
for _, d := range digits {
|
||
|
minLen += d
|
||
|
}
|
||
|
for _, sep := range seps {
|
||
|
minLen += len(sep)
|
||
|
}
|
||
|
|
||
|
m.digits = digits
|
||
|
m.seps = seps
|
||
|
m.minLen = minLen
|
||
|
|
||
|
return m, nil
|
||
|
}
|