diff --git a/main.go b/main.go index 3be83e8..66daf99 100644 --- a/main.go +++ b/main.go @@ -178,14 +178,21 @@ func main() { re_postfix := shuntingYard(re) // fmt.Println(re_postfix) startState := thompson(re_postfix) - start, end, matched := match(startState, os.Args[2]) - if matched { + matchIndices := match(startState, os.Args[2]) + inColor := false + if len(matchIndices) > 0 { for i, c := range os.Args[2] { - if i >= start && i < end { - color.New(color.FgRed).Printf("%c", c) - } else { + for _, indices := range matchIndices { + if i >= indices.startIdx && i < indices.endIdx { + color.New(color.FgRed).Printf("%c", c) + inColor = true + break + } + } + if inColor == false { fmt.Printf("%c", c) } + inColor = false } fmt.Printf("\n") } else { diff --git a/matching.go b/matching.go index d2136a0..e248927 100644 --- a/matching.go +++ b/matching.go @@ -1,5 +1,11 @@ package main +// a matchIndex represents a match. It contains the start index and end index of the match +type matchIndex struct { + startIdx int + endIdx int +} + // takeZeroState takes the 0-state (if such a transition exists) for all states in the // given slice. It returns the resulting states. If any of the resulting states is a 0-state, // the second parameter is true. @@ -19,7 +25,17 @@ func takeZeroState(states []*State) (rtv []*State, isZero bool) { // match tries to match the regex represented by given start-state, with // the given string -func match(start *State, str string) (startIdx int, endIdx int, matched bool) { +func match(start *State, str string) (indices []matchIndex) { + return matchHelper(start, str, make([]matchIndex, 0), 0) +} +func matchHelper(start *State, str string, indices []matchIndex, offset int) []matchIndex { + // 'Base case' - exit if string is empty + if len(str) == 0 { + return indices + } + + startIdx := 0 + endIdx := 0 currentStates := make([]*State, 0) tempStates := make([]*State, 0) // Used to store states that should be used in next loop iteration i := 0 // Index in string @@ -28,12 +44,12 @@ func match(start *State, str string) (startIdx int, endIdx int, matched bool) { for i < len(str) && int(str[i]) != start.content { i++ } + startIdx = i i++ // Advance to next character (if we aren't at a 0-state, which doesn't match anything), so that we can check for transitions. If we advance at a 0-state, we will never get a chance to match the first character } // TODO - If start state is kleene star, try to match the next state currentStates = append(currentStates, start) - startIdx = i // Main loop for i < len(str) { @@ -57,8 +73,10 @@ func match(start *State, str string) (startIdx int, endIdx int, matched bool) { // This enables the 'greedy' behavior - last-state status is only checked if we can't match anything else if state.isLast { endIdx = i - return startIdx, endIdx, true + indices = append(indices, matchIndex{startIdx + offset, endIdx + offset}) } + // Recursion - match with rest of string + return matchHelper(start, str[i:], indices, offset+i) } } currentStates = make([]*State, len(tempStates)) @@ -80,12 +98,10 @@ func match(start *State, str string) (startIdx int, endIdx int, matched bool) { for _, state := range currentStates { if state.isLast { endIdx = i - return startIdx, endIdx, true - } else { - return -1, -1, false + indices = append(indices, matchIndex{startIdx + offset, endIdx + offset}) } } // Default - return -1, -1, false + return indices }