From f58b706285fd96946d35f5a4e9f97c9dc3b6fcd3 Mon Sep 17 00:00:00 2001 From: dudaodong Date: Wed, 4 Dec 2024 16:37:46 +0800 Subject: [PATCH] fix: fix issue #275 --- compare/compare_internal.go | 17 +++++++- convertor/convertor_internal.go | 14 ++++++- docs/strutil.md | 35 ++++++++++++++++ docs/strutil_zh-CN.md | 36 +++++++++++++++- strutil/string.go | 13 ++++-- strutil/string_test.go | 74 +++++++++++++++++++++++++++++++++ 6 files changed, 182 insertions(+), 7 deletions(-) diff --git a/compare/compare_internal.go b/compare/compare_internal.go index 64a9829..e363a18 100644 --- a/compare/compare_internal.go +++ b/compare/compare_internal.go @@ -37,7 +37,8 @@ func compareRefValue(operator string, leftObj, rightObj interface{}, kind reflec case reflect.Struct: // compare time - if leftVal.CanConvert(timeType) { + // fix: issue #275 + if canConvert(leftObj, timeType) { timeObj1, ok := leftObj.(time.Time) if !ok { timeObj1 = leftVal.Convert(timeType).Interface().(time.Time) @@ -59,7 +60,7 @@ func compareRefValue(operator string, leftObj, rightObj interface{}, kind reflec case reflect.Slice: // compare []byte - if leftVal.CanConvert(bytesType) { + if canConvert(leftObj, bytesType) { bytesObj1, ok := leftObj.([]byte) if !ok { bytesObj1 = leftVal.Convert(bytesType).Interface().([]byte) @@ -282,3 +283,15 @@ func compareBools(operator string, left, right bool) bool { } return false } + +// canConvert checks if the value can be converted to the target type +func canConvert(value interface{}, targetType reflect.Type) bool { + v := reflect.ValueOf(value) + + defer func() { + if r := recover(); r != nil { + } + }() + v.Convert(targetType) + return true +} diff --git a/convertor/convertor_internal.go b/convertor/convertor_internal.go index 796c9d3..0f26a72 100644 --- a/convertor/convertor_internal.go +++ b/convertor/convertor_internal.go @@ -240,7 +240,8 @@ func setStructField(structObj interface{}, fieldName string, fieldValue interfac if fieldVal.Type() != val.Type() { - if val.CanConvert(fieldVal.Type()) { + // fix: issue #275 + if canConvert(fieldValue, fieldVal.Type()) { fieldVal.Set(val.Convert(fieldVal.Type())) return nil } @@ -284,3 +285,14 @@ func getFieldNameByJsonTag(structObj interface{}, jsonTag string) string { return "" } + +func canConvert(value interface{}, targetType reflect.Type) bool { + v := reflect.ValueOf(value) + + defer func() { + if r := recover(); r != nil { + } + }() + v.Convert(targetType) + return true +} diff --git a/docs/strutil.md b/docs/strutil.md index fc9ddbb..f99210f 100644 --- a/docs/strutil.md +++ b/docs/strutil.md @@ -66,6 +66,7 @@ import ( - [Rotate](#Rotate) - [TemplateReplace](#TemplateReplace) - [RegexMatchAllGroups](#RegexMatchAllGroups) +- [Cut](#Cut)
@@ -1537,4 +1538,38 @@ func main() { // [john.doe@example.com john.doe example com] // [jane.doe@example.com jane.doe example com] } +``` + +### Cut + +

Splits the string at the first occurrence of separator.

+ +Signature: + +```go +func Cut(str, sep string) (before, after string, found bool) +``` + +example: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + str := "hello-world" + + before, after, found := strutil.Cut("hello-world", "-") + + fmt.Println(before) + fmt.Println(after) + fmt.Println(found) + + // Output: + // hello + // world + // true +} ``` \ No newline at end of file diff --git a/docs/strutil_zh-CN.md b/docs/strutil_zh-CN.md index a33c4af..93dbdc6 100644 --- a/docs/strutil_zh-CN.md +++ b/docs/strutil_zh-CN.md @@ -66,6 +66,7 @@ import ( - [Rotate](#Rotate) - [TemplateReplace](#TemplateReplace) - [RegexMatchAllGroups](#RegexMatchAllGroups) +- [Cut](#Cut)
@@ -1572,4 +1573,37 @@ func main() { // [john.doe@example.com john.doe example com] // [jane.doe@example.com jane.doe example com] } -``` \ No newline at end of file +``` + +### Cut + +

分割字符串。

+ +函数签名: + +```go +func Cut(str, sep string) (before, after string, found bool) +``` + +示例: + +```go +import ( + "fmt" + "github.com/duke-git/lancet/strutil" +) + +func main() { + str := "hello-world" + + before, after, found := strutil.Cut("hello-world", "-") + + fmt.Println(before) + fmt.Println(after) + fmt.Println(found) + + // Output: + // hello + // world + // true +} \ No newline at end of file diff --git a/strutil/string.go b/strutil/string.go index 870ec8b..0da6b6c 100644 --- a/strutil/string.go +++ b/strutil/string.go @@ -535,15 +535,22 @@ func RemoveWhiteSpace(str string, repalceAll bool) string { // SubInBetween return substring between the start and end position(excluded) of source string. func SubInBetween(str string, start string, end string) string { - if _, after, ok := strings.Cut(str, start); ok { - if before, _, ok := strings.Cut(after, end); ok { + if _, after, ok := Cut(str, start); ok { + if before, _, ok := Cut(after, end); ok { return before } } - return "" } +// Cut splits the string at the first occurrence of separator. +func Cut(str, sep string) (before, after string, found bool) { + if i := strings.Index(str, sep); i >= 0 { + return str[:i], str[i+len(sep):], true + } + return str, "", false +} + // HammingDistance calculates the Hamming distance between two strings. // The Hamming distance is the number of positions at which the corresponding symbols are different. // This func returns an error if the input strings are of unequal lengths. diff --git a/strutil/string_test.go b/strutil/string_test.go index 163c144..424608f 100644 --- a/strutil/string_test.go +++ b/strutil/string_test.go @@ -668,3 +668,77 @@ func TestRegexMatchAllGroups(t *testing.T) { assert.Equal(tt.expected, result) } } + +func TestCut(t *testing.T) { + t.Parallel() + + assert := internal.NewAssert(t, "TestCut") + + tests := []struct { + name string + s string + sep string + before string + after string + found bool + }{ + { + name: "test with separator", + s: "hello-world", + sep: "-", + before: "hello", + after: "world", + found: true, + }, + { + name: "test without separator", + s: "helloworld", + sep: "-", + before: "helloworld", + after: "", + found: false, + }, + { + name: "test empty string", + s: "", + sep: "-", + before: "", + after: "", + found: false, + }, + { + name: "test separator at the beginning", + s: "-hello", + sep: "-", + before: "", + after: "hello", + found: true, + }, + { + name: "test separator at the end", + s: "hello-", + sep: "-", + before: "hello", + after: "", + found: true, + }, + { + name: "test multiple separators", + s: "a-b-c-d", + sep: "-", + before: "a", + after: "b-c-d", + found: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + before, after, found := Cut(tt.s, tt.sep) + assert.Equal(tt.before, before) + assert.Equal(tt.after, after) + assert.Equal(tt.found, found) + }) + } + +}