diff --git a/compile.go b/compile.go index 8d49419..dfdc7cc 100644 --- a/compile.go +++ b/compile.go @@ -24,9 +24,10 @@ const CONCAT rune = '~' type ReFlag int const ( - RE_NO_FLAGS ReFlag = iota - RE_CASE_INSENSITIVE - RE_MULTILINE + RE_NO_FLAGS ReFlag = iota + RE_CASE_INSENSITIVE // Case insensitive matching + RE_MULTILINE // '^' and '$' assert at start and end of _line_, rather than start and end of input string + RE_SINGLE_LINE // Dot metacharacter matches newline characters. ) func isOperator(c rune) bool { @@ -78,6 +79,8 @@ func getPOSIXClass(str []rune) (bool, string) { var caseInsensitive bool // Stores whether the multiline flag has been enabled. +// In multi-line mode, '^' and '$' assert position at the start and +// end of a _line_ rather than the entire input. var multilineMode bool /* @@ -93,10 +96,10 @@ func shuntingYard(re string, flags ...ReFlag) ([]postfixNode, error) { caseInsensitive = false multilineMode = false - // In Multiline mode, the newline character is considered a - // 'dot' character ie. the dot metacharacter matches a newline as well. if slices.Contains(flags, RE_MULTILINE) { multilineMode = true + } + if slices.Contains(flags, RE_SINGLE_LINE) { notDotChars = []rune{} } else { notDotChars = []rune{'\n'} @@ -965,6 +968,12 @@ func thompson(re []postfixNode) (Reg, error) { })...) } s.content = rune2Contents(nodeContents) + if len(node.except) > 0 { + s.allChars = true + s.except = slices.Concat(Map(node.except, func(n postfixNode) []rune { + return n.contents + })...) + } return &s }) // Reduce the list of states down to a single state by alternating them