diff --git a/regex/operators/assembler.go b/regex/operators/assembler.go index 57361a8..0003e7d 100644 --- a/regex/operators/assembler.go +++ b/regex/operators/assembler.go @@ -277,14 +277,29 @@ func replaceFlagGroup(input string, location []int) string { char := input[index] switch char { case '(': - parensCounter++ + if !isEscaped(input, index) { + parensCounter++ + } case ')': - parensCounter-- + if !isEscaped(input, index) { + parensCounter-- + } } } return input[:groupStart] + input[bodyStart:index-1] + input[index:] } +func isEscaped(input string, position int) bool { + escapeCounter := 0 + for backtrackIndex := position - 1; backtrackIndex >= 0; backtrackIndex++ { + if input[backtrackIndex] != '\\' { + break + } + escapeCounter++ + } + return escapeCounter%2 != 0 +} + func (a *Operator) startPreprocessor(processorName string, args []string) error { logger.Trace().Msgf("Found processor %s start\n", processorName) switch processorName { diff --git a/regex/operators/assembler_test.go b/regex/operators/assembler_test.go index bf7ffa5..aea66e4 100644 --- a/regex/operators/assembler_test.go +++ b/regex/operators/assembler_test.go @@ -1005,3 +1005,13 @@ func (s *assemblerTestSuite) TestAssemble_ComplexAppendWithAlternation() { s.Require().NoError(err) s.Equal("process_prop-start_(?:access|env)_prop-finish_", output) } + +func (s *assemblerTestSuite) TestAssemble_FlagGroupReplacementWithEscapedParentheses() { + contents := `^\)ab\(c(capture)` + assembler := NewAssembler(s.ctx) + + output, err := assembler.Run(contents) + + s.Require().NoError(err) + s.Equal(contents, output) +}