Implement matching logic for literals and character classes; add test data
This commit is contained in:
113
main.go
113
main.go
@@ -153,7 +153,101 @@ func buildComponents(pattern string) ([]Component, error) {
|
|||||||
return comps, nil
|
return comps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func matchEngine(pattern string, line string, lineNum int, exp bool) {
|
// ---------- match a single literal (with repeat) ----------
|
||||||
|
func matchLiteral(l Character, runes []rune, pos *int) bool {
|
||||||
|
switch l.Repeats {
|
||||||
|
case NoRepeat:
|
||||||
|
if *pos >= len(runes) || runes[*pos] != l.Character {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
(*pos)++
|
||||||
|
return true
|
||||||
|
|
||||||
|
case ZeroOrMore:
|
||||||
|
for *pos < len(runes) && runes[*pos] == l.Character {
|
||||||
|
(*pos)++
|
||||||
|
}
|
||||||
|
return true // zero occurrences are fine
|
||||||
|
|
||||||
|
case OneOrMore:
|
||||||
|
if *pos >= len(runes) || runes[*pos] != l.Character {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for *pos < len(runes) && runes[*pos] == l.Character {
|
||||||
|
(*pos)++
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func inClass(rc RenderedCharacterClass, r rune) bool {
|
||||||
|
for _, cr := range rc.Characters {
|
||||||
|
if r == cr {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchClass(rc RenderedCharacterClass, runes []rune, pos *int) bool {
|
||||||
|
switch rc.Repeats {
|
||||||
|
case NoRepeat:
|
||||||
|
if *pos >= len(runes) || !inClass(rc, runes[*pos]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
(*pos)++
|
||||||
|
return true
|
||||||
|
|
||||||
|
case ZeroOrMore:
|
||||||
|
for *pos < len(runes) && inClass(rc, runes[*pos]) {
|
||||||
|
(*pos)++
|
||||||
|
}
|
||||||
|
return true // zero occurrences are fine
|
||||||
|
|
||||||
|
case OneOrMore:
|
||||||
|
if *pos >= len(runes) || !inClass(rc, runes[*pos]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for *pos < len(runes) && inClass(rc, runes[*pos]) {
|
||||||
|
(*pos)++
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchFrom(components []Component, runes []rune, pos int) bool {
|
||||||
|
for _, c := range components {
|
||||||
|
switch c.Ctype {
|
||||||
|
case Literal:
|
||||||
|
if !matchLiteral(c.Literal, runes, &pos) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case Rendered:
|
||||||
|
if !matchClass(c.Rendered, runes, &pos) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchComponents(components []Component, text string) bool {
|
||||||
|
runes := []rune(text)
|
||||||
|
for start := 0; start <= len(runes); start++ {
|
||||||
|
if matchFrom(components, runes, start) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func matchEngine(pattern string, line string, lineNum int, exp bool, components []Component) error {
|
||||||
if !exp {
|
if !exp {
|
||||||
// sliding window approach for simple full pattern matching
|
// sliding window approach for simple full pattern matching
|
||||||
for i := 0; i < len(line)-len(pattern); i++ {
|
for i := 0; i < len(line)-len(pattern); i++ {
|
||||||
@@ -163,11 +257,20 @@ func matchEngine(pattern string, line string, lineNum int, exp bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if matchComponents(components, line) {
|
||||||
|
println(lineNum, line)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func processReader(r *os.File, pattern string, exp bool) {
|
func processReader(r *os.File, pattern string, exp bool) {
|
||||||
|
var components []Component
|
||||||
|
if exp {
|
||||||
|
components, _ = buildComponents(pattern)
|
||||||
|
}
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
scanner := bufio.NewScanner(r)
|
scanner := bufio.NewScanner(r)
|
||||||
lineN := 0
|
lineN := 0
|
||||||
@@ -175,10 +278,10 @@ func processReader(r *os.File, pattern string, exp bool) {
|
|||||||
lineN++
|
lineN++
|
||||||
text := scanner.Text()
|
text := scanner.Text()
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func(ln int) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
matchEngine(pattern, text, lineN, exp)
|
matchEngine(pattern, text, ln, exp, components)
|
||||||
}()
|
}(lineN)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|||||||
Reference in New Issue
Block a user