diff --git a/processor/regex.go b/processor/regex.go index 9dab03a..add4bab 100644 --- a/processor/regex.go +++ b/processor/regex.go @@ -80,6 +80,20 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr log.Printf("Pattern modified to include (?s): %s", pattern) } + // The order of these replaces is important + // This one handles !num-s inside of named capture groups + // If it were not here our !num in a named capture group would + // Expand to another capture group in the capture group + // We really only want one (our named) capture group + namedGroupNum := regexp.MustCompile(`(?:(\?<[^>]+>)(!num))`) + pattern = namedGroupNum.ReplaceAllStringFunc(pattern, func(match string) string { + parts := namedGroupNum.FindStringSubmatch(match) + if len(parts) != 3 { + return match + } + replacement := `\d*\.?\d+` + return parts[1] + replacement + }) pattern = strings.ReplaceAll(pattern, "!num", `"?(\d*\.?\d+)"?`) pattern = strings.ReplaceAll(pattern, "!any", `.*?`) repPattern := regexp.MustCompile(`!rep\(([^,]+),\s*(\d+)\)`) @@ -125,7 +139,7 @@ func (p *RegexProcessor) ProcessContent(content string, pattern string, luaExpr log.Printf("Error creating Lua state: %v", err) return "", 0, 0, fmt.Errorf("error creating Lua state: %v", err) } - // Hmm... Maybe we don't want to defer this.. + // Hmm... Maybe we don't want to defer this.. // Maybe we want to close them every iteration // We'll leave it as is for now defer L.Close() diff --git a/processor/regex_test.go b/processor/regex_test.go index e1f3f87..508d5ca 100644 --- a/processor/regex_test.go +++ b/processor/regex_test.go @@ -581,6 +581,39 @@ func TestNamedCaptureGroups(t *testing.T) { } } +func TestNamedCaptureGroupsNum(t *testing.T) { + content := ` + + 100 + +` + + expected := ` + + 200 + +` + + p := &RegexProcessor{} + result, mods, matches, err := p.ProcessContent(content, `(?s)(?!num)`, "amount = amount * 2") + + if err != nil { + t.Fatalf("Error processing content: %v", err) + } + + if matches != 1 { + t.Errorf("Expected 1 match, got %d", matches) + } + + if mods != 1 { + t.Errorf("Expected 1 modification, got %d", mods) + } + + if result != expected { + t.Errorf("Expected content to be:\n%s\n\nGot:\n%s", expected, result) + } +} + func TestMultipleNamedCaptureGroups(t *testing.T) { content := ` Widget