From 05e6ac2ab64bbfb3b0ece82156906edbe794b140 Mon Sep 17 00:00:00 2001 From: hunshcn Date: Sat, 24 Feb 2024 10:28:33 +0800 Subject: [PATCH] Support JSON Marshal/Unmarshal (#77) Support JSON Marshal/Unmarshal --- regexp.go | 28 +++++++++++++++++++++++++--- regexp_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/regexp.go b/regexp.go index c8f9e6b..a7ddbaf 100644 --- a/regexp.go +++ b/regexp.go @@ -18,8 +18,12 @@ import ( "github.com/dlclark/regexp2/syntax" ) -// Default timeout used when running regexp matches -- "forever" -var DefaultMatchTimeout = time.Duration(math.MaxInt64) +var ( + // DefaultMatchTimeout used when running regexp matches -- "forever" + DefaultMatchTimeout = time.Duration(math.MaxInt64) + // DefaultUnmarshalOptions used when unmarshaling a regex from text + DefaultUnmarshalOptions = None +) // Regexp is the representation of a compiled regular expression. // A Regexp is safe for concurrent use by multiple goroutines. @@ -43,7 +47,7 @@ type Regexp struct { code *syntax.Code // compiled program // cache of machines for running regexp - muRun sync.Mutex + muRun *sync.Mutex runner []*runner } @@ -72,6 +76,7 @@ func Compile(expr string, opt RegexOptions) (*Regexp, error) { capsize: code.Capsize, code: code, MatchTimeout: DefaultMatchTimeout, + muRun: &sync.Mutex{}, }, nil } @@ -371,3 +376,20 @@ func (re *Regexp) GroupNumberFromName(name string) int { return -1 } + +// MarshalText implements [encoding.TextMarshaler]. The output +// matches that of calling the [Regexp.String] method. +func (re *Regexp) MarshalText() ([]byte, error) { + return []byte(re.String()), nil +} + +// UnmarshalText implements [encoding.TextUnmarshaler] by calling +// [Compile] on the encoded value. +func (re *Regexp) UnmarshalText(text []byte) error { + newRE, err := Compile(string(text), DefaultUnmarshalOptions) + if err != nil { + return err + } + *re = *newRE + return nil +} diff --git a/regexp_test.go b/regexp_test.go index cc6323b..d4562e5 100644 --- a/regexp_test.go +++ b/regexp_test.go @@ -1,6 +1,7 @@ package regexp2 import ( + "encoding/json" "fmt" "reflect" "strings" @@ -1329,3 +1330,37 @@ func TestParseShortSlashPEnd(t *testing.T) { t.Fatalf("Expected match") } } + +func TestMarshal(t *testing.T) { + re := MustCompile(`.*`, 0) + m, err := json.Marshal(re) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if string(m) != `".*"` { + t.Fatalf(`Expected ".*"`) + } +} + +func TestUnMarshal(t *testing.T) { + DefaultUnmarshalOptions = IgnoreCase + bytes := []byte(`"^[abc]"`) + var re *Regexp + err := json.Unmarshal(bytes, &re) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if re.options != IgnoreCase { + t.Fatalf("Expected options ignore case") + } + if re.String() != `^[abc]` { + t.Fatalf(`Expected "^[abc]"`) + } + ok, err := re.MatchString("A") + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if !ok { + t.Fatalf(`Expected match`) + } +}