Implement matching logic for literals and character classes; add test data

This commit is contained in:
2026-01-15 17:26:00 +01:00
parent a0df0dd7fe
commit 73c53b1cba
2 changed files with 123 additions and 5 deletions

113
main.go
View File

@@ -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()

15
test.txt Normal file
View File

@@ -0,0 +1,15 @@
xx123abcx987
testtesttest324525wgefwrftas
fgsdhfjklguz,
fgsdhfjklguz,
xx123abcx987
xx123abcx987
xx123ab
cx987