add gregex.ReplaceFuncMatch/ReplaceStringFuncMatch functions for package gregex

This commit is contained in:
John
2019-04-23 14:15:12 +08:00
parent 5d04c2e50a
commit a9f9261dbd
3 changed files with 96 additions and 30 deletions

View File

@ -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 <pattern> valid.
//
// 校验所给定的正则表达式是否符合规范
func Validate(pattern string) error {
_, err := getRegexp(pattern)
return err
}
// IsMatch checks whether given bytes <src> matches <pattern>.
//
// 正则表达式是否匹配
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 <src> matches <pattern>.
//
// 判断给定的字符串<src>是否满足正则表达式<pattern>.
func IsMatchString(pattern string, src string) bool {
return IsMatch(pattern, []byte(src))
}
// MatchString return bytes slice that matched <pattern>.
//
// 正则匹配,并返回匹配的列表(参数[]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 <pattern>.
//
// 正则匹配,并返回匹配的列表(参数[]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 <pattern>.
//
// 正则匹配,并返回所有匹配的列表(参数[]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 <pattern>.
//
// 正则匹配,并返回所有匹配的列表(参数[][]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 <pattern> in bytes <src> with bytes <replace>.
//
// 正则替换(全部替换).
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 <pattern> in string <src> with string <replace>.
//
// 正则替换(全部替换),字符串
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 <pattern> in bytes <src>
// with custom replacement function <replaceFunc>.
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 <pattern> in bytes <src>
// with custom replacement function <replaceFunc>.
// The parameter <match> type for <replaceFunc> is [][]byte,
// which is the result contains all sub-patterns of <pattern> 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 <pattern> in string <src>
@ -129,6 +124,21 @@ func ReplaceStringFunc(pattern string, src string, replaceFunc func(s string) st
return string(bytes), err
}
// ReplaceStringFuncMatch replace all matched <pattern> in string <src>
// with custom replacement function <replaceFunc>.
// The parameter <match> type for <replaceFunc> is []string,
// which is the result contains all sub-patterns of <pattern> 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 <src> into substrings separated by the expression and returns a slice of
// the substrings between those expression matches.
func Split(pattern string, src string) []string {

View File

@ -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 <pattern>.
// 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 <pattern>, 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

View File

@ -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"