diff --git a/g/text/gregex/gregex.go b/g/text/gregex/gregex.go index 50903a13a..0c00bc89b 100644 --- a/g/text/gregex/gregex.go +++ b/g/text/gregex/gregex.go @@ -5,8 +5,6 @@ // You can obtain one at https://github.com/gogf/gf. // Package gregex provides high performance API for regular expression functionality. -// -// 正则表达式. package gregex import ( @@ -17,22 +15,18 @@ import ( // to match the rules of regular expression pattern. // And returns the copy. // -// 转移正则规则字符串,例如:Quote(`[foo]`) 返回 `\[foo\]` +// Eg: Quote(`[foo]`) returns `\[foo\]`. func Quote(s string) string { return regexp.QuoteMeta(s) } // Validate checks whether given regular expression pattern valid. -// -// 校验所给定的正则表达式是否符合规范 func Validate(pattern string) error { _, err := getRegexp(pattern) return err } // IsMatch checks whether given bytes matches . -// -// 正则表达式是否匹配 func IsMatch(pattern string, src []byte) bool { if r, err := getRegexp(pattern); err == nil { return r.Match(src) @@ -41,15 +35,11 @@ func IsMatch(pattern string, src []byte) bool { } // IsMatchString checks whether given string matches . -// -// 判断给定的字符串是否满足正则表达式. func IsMatchString(pattern string, src string) bool { return IsMatch(pattern, []byte(src)) } // MatchString return bytes slice that matched . -// -// 正则匹配,并返回匹配的列表(参数[]byte) func Match(pattern string, src []byte) ([][]byte, error) { if r, err := getRegexp(pattern); err == nil { return r.FindSubmatch(src), nil @@ -59,8 +49,6 @@ func Match(pattern string, src []byte) ([][]byte, error) { } // MatchString return strings that matched . -// -// 正则匹配,并返回匹配的列表(参数[]string) func MatchString(pattern string, src string) ([]string, error) { if r, err := getRegexp(pattern); err == nil { return r.FindStringSubmatch(src), nil @@ -70,8 +58,6 @@ func MatchString(pattern string, src string) ([]string, error) { } // MatchAll return all bytes slices that matched . -// -// 正则匹配,并返回所有匹配的列表(参数[]string) func MatchAll(pattern string, src []byte) ([][][]byte, error) { if r, err := getRegexp(pattern); err == nil { return r.FindAllSubmatch(src, -1), nil @@ -81,8 +67,6 @@ func MatchAll(pattern string, src []byte) ([][][]byte, error) { } // MatchAllString return all strings that matched . -// -// 正则匹配,并返回所有匹配的列表(参数[][]string). func MatchAllString(pattern string, src string) ([][]string, error) { if r, err := getRegexp(pattern); err == nil { return r.FindAllStringSubmatch(src, -1), nil @@ -92,8 +76,6 @@ func MatchAllString(pattern string, src string) ([][]string, error) { } // ReplaceString replace all matched in bytes with bytes . -// -// 正则替换(全部替换). func Replace(pattern string, replace, src []byte) ([]byte, error) { if r, err := getRegexp(pattern); err == nil { return r.ReplaceAll(src, replace), nil @@ -103,8 +85,6 @@ func Replace(pattern string, replace, src []byte) ([]byte, error) { } // ReplaceString replace all matched in string with string . -// -// 正则替换(全部替换),字符串 func ReplaceString(pattern, replace, src string) (string, error) { r, e := Replace(pattern, []byte(replace), []byte(src)) return string(r), e @@ -113,11 +93,26 @@ func ReplaceString(pattern, replace, src string) (string, error) { // ReplaceFunc replace all matched in bytes // with custom replacement function . func ReplaceFunc(pattern string, src []byte, replaceFunc func(b []byte) []byte) ([]byte, error) { - if r, err := getRegexp(pattern); err == nil { - return r.ReplaceAllFunc(src, replaceFunc), nil - } else { - return nil, err - } + if r, err := getRegexp(pattern); err == nil { + return r.ReplaceAllFunc(src, replaceFunc), nil + } else { + return nil, err + } +} + +// ReplaceFunc replace all matched in bytes +// with custom replacement function . +// The parameter type for is [][]byte, +// which is the result contains all sub-patterns of using Match function. +func ReplaceFuncMatch(pattern string, src []byte, replaceFunc func(match [][]byte) []byte) ([]byte, error) { + if r, err := getRegexp(pattern); err == nil { + return r.ReplaceAllFunc(src, func(bytes []byte) []byte { + match, _ := Match(pattern, src) + return replaceFunc(match) + }), nil + } else { + return nil, err + } } // ReplaceStringFunc replace all matched in string @@ -129,6 +124,21 @@ func ReplaceStringFunc(pattern string, src string, replaceFunc func(s string) st return string(bytes), err } +// ReplaceStringFuncMatch replace all matched in string +// with custom replacement function . +// The parameter type for is []string, +// which is the result contains all sub-patterns of using MatchString function. +func ReplaceStringFuncMatch(pattern string, src string, replaceFunc func(match []string) string) (string, error) { + if r, err := getRegexp(pattern); err == nil { + return string(r.ReplaceAllFunc([]byte(src), func(bytes []byte) []byte { + match, _ := MatchString(pattern, src) + return []byte(replaceFunc(match)) + })), nil + } else { + return "", err + } +} + // Split slices into substrings separated by the expression and returns a slice of // the substrings between those expression matches. func Split(pattern string, src string) []string { diff --git a/g/text/gregex/gregex_cache.go b/g/text/gregex/gregex_cache.go index b0a68fb0b..f3ee27b6d 100644 --- a/g/text/gregex/gregex_cache.go +++ b/g/text/gregex/gregex_cache.go @@ -11,13 +11,15 @@ import ( "sync" ) -// 缓存对象,主要用于缓存底层regx对象 var ( regexMu = sync.RWMutex{} regexMap = make(map[string]*regexp.Regexp) ) -// 根据pattern生成对应的regexp正则对象 +// getRegexp returns *regexp.Regexp object with given . +// It uses cache to enhance the performance for compiling regular expression pattern, +// which means, it will return the same *regexp.Regexp object with the same regular +// expression pattern. func getRegexp(pattern string) (*regexp.Regexp, error) { if r := getCache(pattern); r != nil { return r, nil @@ -30,7 +32,7 @@ func getRegexp(pattern string) (*regexp.Regexp, error) { } } -// 获得正则缓存对象 +// getCache returns *regexp.Regexp object from cache by given , for internal usage. func getCache(pattern string) (regex *regexp.Regexp) { regexMu.RLock() regex = regexMap[pattern] @@ -38,7 +40,7 @@ func getCache(pattern string) (regex *regexp.Regexp) { return } -// 设置正则缓存对象 +// setCache stores *regexp.Regexp object into cache, for internal usage. func setCache(pattern string, regex *regexp.Regexp) { regexMu.Lock() regexMap[pattern] = regex diff --git a/g/text/gregex/gregex_z_unit_test.go b/g/text/gregex/gregex_z_unit_test.go index 94acb37f6..64ce85489 100644 --- a/g/text/gregex/gregex_z_unit_test.go +++ b/g/text/gregex/gregex_z_unit_test.go @@ -185,6 +185,33 @@ func Test_ReplaceFun(t *testing.T) { }) } +func Test_ReplaceFuncMatch(t *testing.T) { + gtest.Case(t, func() { + s := []byte("1234567890") + p := `(\d{3})(\d{3})(.+)` + s0, e0 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte { + return match[0] + }) + gtest.Assert(e0, nil) + gtest.Assert(s0, s) + s1, e1 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte { + return match[1] + }) + gtest.Assert(e1, nil) + gtest.Assert(s1, []byte("123")) + s2, e2 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte { + return match[2] + }) + gtest.Assert(e2, nil) + gtest.Assert(s2, []byte("456")) + s3, e3 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte { + return match[3] + }) + gtest.Assert(e3, nil) + gtest.Assert(s3, []byte("7890")) + }) +} + func Test_ReplaceStringFunc(t *testing.T) { gtest.Case(t, func() { re := "a(a+b+)b" @@ -206,6 +233,33 @@ func Test_ReplaceStringFunc(t *testing.T) { }) } +func Test_ReplaceStringFuncMatch(t *testing.T) { + gtest.Case(t, func() { + s := "1234567890" + p := `(\d{3})(\d{3})(.+)` + s0, e0 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string { + return match[0] + }) + gtest.Assert(e0, nil) + gtest.Assert(s0, s) + s1, e1 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string { + return match[1] + }) + gtest.Assert(e1, nil) + gtest.Assert(s1, "123") + s2, e2 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string { + return match[2] + }) + gtest.Assert(e2, nil) + gtest.Assert(s2, "456") + s3, e3 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string { + return match[3] + }) + gtest.Assert(e3, nil) + gtest.Assert(s3, "7890") + }) +} + func Test_Split(t *testing.T) { gtest.Case(t, func() { re := "a(a+b+)b"