1
0
mirror of https://github.com/duke-git/lancet.git synced 2026-02-23 13:52:26 +08:00

Compare commits

...

8 Commits

Author SHA1 Message Date
dudaodong
01a3b139c0 doc: add document for new functions in slice and strutil package 2023-04-18 15:49:09 +08:00
dudaodong
fcb3b97b45 doc: add docment and playground demo for v2.1.19 2023-04-18 15:21:03 +08:00
dudaodong
52ea64bc33 feat: add FindLastBy function 2023-04-17 20:17:26 +08:00
燕归来
14bc08c6d6 feat: add FindBy that a result will be without unrefrence #88 (#90)
feat: add example for FindBy

chore: reduce code duplication
2023-04-17 20:11:56 +08:00
dudaodong
47bdd6718a fix: ExecCommand can't compile in macos 2023-04-17 17:03:46 +08:00
dudaodong
18d27604e6 update mod file 2023-04-17 17:00:53 +08:00
dudaodong
66bd339e3a doc: add example for strutil new functions 2023-04-17 16:35:26 +08:00
燕归来
04abb7a3ea feat: add some function for strutil package #88 (#89) 2023-04-17 16:07:14 +08:00
24 changed files with 946 additions and 43 deletions

View File

@@ -543,6 +543,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/g0w34kS7B8m)] [[play](https://go.dev/play/p/g0w34kS7B8m)]
- **<big>CurrentPath</big>** : return current absolute path. - **<big>CurrentPath</big>** : return current absolute path.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CurrentPath)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil.md#CurrentPath)]
[[play](https://go.dev/play/p/s74a9iBGcSw)]
### 9. Formatter contains some functions for data formatting. ### 9. Formatter contains some functions for data formatting.
@@ -557,16 +558,22 @@ import "github.com/duke-git/lancet/v2/formatter"
[[play](https://go.dev/play/p/eRD5k2vzUVX)] [[play](https://go.dev/play/p/eRD5k2vzUVX)]
- **<big>Pretty</big>** : pretty print data to JSON string. - **<big>Pretty</big>** : pretty print data to JSON string.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Pretty)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#Pretty)]
[[play](https://go.dev/play/p/YsciGj3FH2x)]
- **<big>PrettyToWriter</big>** : pretty encode data to writer. - **<big>PrettyToWriter</big>** : pretty encode data to writer.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#PrettyToWriter)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#PrettyToWriter)]
[[play](https://go.dev/play/p/LPLZ3lDi5ma)]
- **<big>DecimalBytes</big>** : returns a human readable byte size under decimal standard (base 1000). - **<big>DecimalBytes</big>** : returns a human readable byte size under decimal standard (base 1000).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#DecimalBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#DecimalBytes)]
[[play](https://go.dev/play/p/FPXs1suwRcs)]
- **<big>BinaryBytes</big>** : returns a human-readable byte size under binary standard (base 1024). - **<big>BinaryBytes</big>** : returns a human-readable byte size under binary standard (base 1024).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#BinaryBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#BinaryBytes)]
[[play](https://go.dev/play/p/G9oHHMCAZxP)]
- **<big>ParseDecimalBytes</big>** : return the human readable bytes size string into the amount it represents(base 1000). - **<big>ParseDecimalBytes</big>** : return the human readable bytes size string into the amount it represents(base 1000).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseDecimalBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseDecimalBytes)]
[[play](https://go.dev/play/p/Am98ybWjvjj)]
- **<big>ParseBinaryBytes</big>** : return the human readable bytes size string into the amount it represents(base 1024). - **<big>ParseBinaryBytes</big>** : return the human readable bytes size string into the amount it represents(base 1024).
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseBinaryBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter.md#ParseBinaryBytes)]
[[play](https://go.dev/play/p/69v1tTT62x8)]
### 10. Function package can control the flow of function execution and support part of functional programming ### 10. Function package can control the flow of function execution and support part of functional programming
@@ -614,6 +621,7 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>MapTo</big>** : quick map any value to struct or any base type. - **<big>MapTo</big>** : quick map any value to struct or any base type.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapTo)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#MapTo)]
[[play](https://go.dev/play/p/4K7KBEPgS5M)]
- **<big>ForEach</big>** : executes iteratee funcation for every key and value pair in map. - **<big>ForEach</big>** : executes iteratee funcation for every key and value pair in map.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil.md#ForEach)]
[[play](https://go.dev/play/p/OaThj6iNVXK)] [[play](https://go.dev/play/p/OaThj6iNVXK)]
@@ -988,11 +996,13 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/8uI8f1lwNrQ)] [[play](https://go.dev/play/p/8uI8f1lwNrQ)]
- **<big>Reduce<sup>deprecated</sup></big>** : creates an slice of values by running each element of slice thru iteratee function.(Deprecated: use ReduceBy) - **<big>Reduce<sup>deprecated</sup></big>** : creates an slice of values by running each element of slice thru iteratee function.(Deprecated: use ReduceBy)
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Reduce)]
[[play](https://go.dev/play/p/_RfXJJWIsIm)]
- **<big>ReduceBy</big>** : produces a value from slice by accumulating the result of each element as passed through the reducer function. - **<big>ReduceBy</big>** : produces a value from slice by accumulating the result of each element as passed through the reducer function.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReduceBy)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReduceBy)]
[[play](https://go.dev/play/p/YKDpLi7gtee)]
- **<big>ReduceRight</big>** : ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left. - **<big>ReduceRight</big>** : ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReduceRight)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#ReduceRight)]
[[play](https://go.dev/play/p/_RfXJJWIsIm)] [[play](https://go.dev/play/p/qT9dZC03A1K)]
- **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new. - **<big>Replace</big>** : returns a copy of the slice with the first n non-overlapping instances of old replaced by new.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice.md#Replace)]
[[play](https://go.dev/play/p/P5mZp7IhOFo)] [[play](https://go.dev/play/p/P5mZp7IhOFo)]
@@ -1351,11 +1361,13 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/dpzgUjFnBCX)] [[play](https://go.dev/play/p/dpzgUjFnBCX)]
- **<big>IsFloat</big>** : check if the value is float(float32, float34) or not. - **<big>IsFloat</big>** : check if the value is float(float32, float34) or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloat)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloat)]
[[play](https://go.dev/play/p/vsyG-sxr99_Z)]
- **<big>IsFloatStr</big>** : check if the string can convert to a float. - **<big>IsFloatStr</big>** : check if the string can convert to a float.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsFloatStr)]
[[play](https://go.dev/play/p/LOYwS_Oyl7U)] [[play](https://go.dev/play/p/LOYwS_Oyl7U)]
- **<big>IsNumber</big>** : check if the value is number(integer, float) or not. - **<big>IsNumber</big>** : check if the value is number(integer, float) or not.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumber)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumber)]
[[play](https://go.dev/play/p/mdJHOAvtsvF)]
- **<big>IsNumberStr</big>** : check if the string can convert to a number. - **<big>IsNumberStr</big>** : check if the string can convert to a number.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsNumberStr)]
[[play](https://go.dev/play/p/LzaKocSV79u)] [[play](https://go.dev/play/p/LzaKocSV79u)]
@@ -1367,6 +1379,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/z_XeZo_litG)] [[play](https://go.dev/play/p/z_XeZo_litG)]
- **<big>IsInt</big>** : check if the string can convert to a number. - **<big>IsInt</big>** : check if the string can convert to a number.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsInt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsInt)]
[[play](https://go.dev/play/p/eFoIHbgzl-z)]
- **<big>IsIntStr</big>** : check if the string can convert to a integer. - **<big>IsIntStr</big>** : check if the string can convert to a integer.
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator.md#IsIntStr)]
[[play](https://go.dev/play/p/jQRtFv-a0Rk)] [[play](https://go.dev/play/p/jQRtFv-a0Rk)]

View File

@@ -542,6 +542,7 @@ import "github.com/duke-git/lancet/v2/fileutil"
[[play](https://go.dev/play/p/g0w34kS7B8m)] [[play](https://go.dev/play/p/g0w34kS7B8m)]
- **<big>CurrentPath</big>** : 返回当前位置的绝对路径。 - **<big>CurrentPath</big>** : 返回当前位置的绝对路径。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CurrentPath)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/fileutil_zh-CN.md#CurrentPath)]
[[play](https://go.dev/play/p/s74a9iBGcSw)]
### 9. formatter 格式化器包含一些数据格式化处理方法。 ### 9. formatter 格式化器包含一些数据格式化处理方法。
@@ -556,16 +557,22 @@ import "github.com/duke-git/lancet/v2/formatter"
[[play](https://go.dev/play/p/eRD5k2vzUVX)] [[play](https://go.dev/play/p/eRD5k2vzUVX)]
- **<big>Pretty</big>** : 返回 pretty JSON 字符串。 - **<big>Pretty</big>** : 返回 pretty JSON 字符串。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Pretty)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#Pretty)]
[[play](https://go.dev/play/p/YsciGj3FH2x)]
- **<big>PrettyToWriter</big>** : Pretty encode 数据到 writer。 - **<big>PrettyToWriter</big>** : Pretty encode 数据到 writer。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#PrettyToWriter)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#PrettyToWriter)]
[[play](https://go.dev/play/p/LPLZ3lDi5ma)]
- **<big>DecimalBytes</big>** : 返回十进制标准(以 1000 为基数下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。 - **<big>DecimalBytes</big>** : 返回十进制标准(以 1000 为基数下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#DecimalBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#DecimalBytes)]
[[play](https://go.dev/play/p/FPXs1suwRcs)]
- **<big>BinaryBytes</big>** : 返回 binary 标准(以 1024 为基数下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。 - **<big>BinaryBytes</big>** : 返回 binary 标准(以 1024 为基数下的可读字节单位字符串。precision 参数指定小数点后的位数,默认为 4。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#BinaryBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#BinaryBytes)]
[[play](https://go.dev/play/p/G9oHHMCAZxP)]
- **<big>ParseDecimalBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1000 为基数)。 - **<big>ParseDecimalBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1000 为基数)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseDecimalBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseDecimalBytes)]
[[play](https://go.dev/play/p/Am98ybWjvjj)]
- **<big>ParseBinaryBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1024 为基数)。 - **<big>ParseBinaryBytes</big>** : 将字节单位字符串转换成其所表示的字节数(以 1024 为基数)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseBinaryBytes)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/formatter_zh-CN.md#ParseBinaryBytes)]
[[play](https://go.dev/play/p/69v1tTT62x8)]
### 10. function 函数包控制函数执行流程,包含部分函数式编程。 ### 10. function 函数包控制函数执行流程,包含部分函数式编程。
@@ -613,6 +620,7 @@ import "github.com/duke-git/lancet/v2/maputil"
- **<big>MapTo</big>** : 快速将 map 或者其他类型映射到结构体或者指定类型。 - **<big>MapTo</big>** : 快速将 map 或者其他类型映射到结构体或者指定类型。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#MapTo)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#MapTo)]
[[play](https://go.dev/play/p/4K7KBEPgS5M)]
- **<big>ForEach</big>** : 对 map 中的每对 key 和 value 执行 iteratee 函数。 - **<big>ForEach</big>** : 对 map 中的每对 key 和 value 执行 iteratee 函数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/maputil_zh-CN.md#ForEach)]
[[play](https://go.dev/play/p/OaThj6iNVXK)] [[play](https://go.dev/play/p/OaThj6iNVXK)]
@@ -990,8 +998,10 @@ import "github.com/duke-git/lancet/v2/slice"
[[play](https://go.dev/play/p/_RfXJJWIsIm)] [[play](https://go.dev/play/p/_RfXJJWIsIm)]
- **<big>ReduceBy</big>** : 对切片元素执行 reduce 操作。 - **<big>ReduceBy</big>** : 对切片元素执行 reduce 操作。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceBy)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceBy)]
[[play](https://go.dev/play/p/YKDpLi7gtee)]
- **<big>ReduceRight</big>** : 类似 ReduceBy 操作,迭代切片元素顺序从右至左。 - **<big>ReduceRight</big>** : 类似 ReduceBy 操作,迭代切片元素顺序从右至左。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceRight)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#ReduceRight)]
[[play](https://go.dev/play/p/qT9dZC03A1K)]
- **<big>Replace</big>** : 返回切片的副本,其中前 n 个不重叠的 old 替换为 new。 - **<big>Replace</big>** : 返回切片的副本,其中前 n 个不重叠的 old 替换为 new。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Replace)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/slice_zh-CN.md#Replace)]
[[play](https://go.dev/play/p/P5mZp7IhOFo)] [[play](https://go.dev/play/p/P5mZp7IhOFo)]
@@ -1353,11 +1363,13 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/dpzgUjFnBCX)] [[play](https://go.dev/play/p/dpzgUjFnBCX)]
- **<big>IsFloat</big>** : 验证参数是否是浮点数((float32float34)。 - **<big>IsFloat</big>** : 验证参数是否是浮点数((float32float34)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloat)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloat)]
[[play](https://go.dev/play/p/vsyG-sxr99_Z)]
- **<big>IsFloatStr</big>** : 验证字符串是否是可以转换为浮点数。 - **<big>IsFloatStr</big>** : 验证字符串是否是可以转换为浮点数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsFloatStr)]
[[play](https://go.dev/play/p/LOYwS_Oyl7U)] [[play](https://go.dev/play/p/LOYwS_Oyl7U)]
- **<big>IsNumber</big>** : 验证参数是否是数字(integerfloat)。 - **<big>IsNumber</big>** : 验证参数是否是数字(integerfloat)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumber)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumber)]
[[play](https://go.dev/play/p/mdJHOAvtsvF)]
- **<big>IsNumberStr</big>** : 验证字符串是否是可以转换为数字。 - **<big>IsNumberStr</big>** : 验证字符串是否是可以转换为数字。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsNumberStr)]
[[play](https://go.dev/play/p/LzaKocSV79u)] [[play](https://go.dev/play/p/LzaKocSV79u)]
@@ -1369,6 +1381,7 @@ import "github.com/duke-git/lancet/v2/validator"
[[play](https://go.dev/play/p/z_XeZo_litG)] [[play](https://go.dev/play/p/z_XeZo_litG)]
- **<big>IsInt</big>** : 验证参数是否是整数(int, unit)。 - **<big>IsInt</big>** : 验证参数是否是整数(int, unit)。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsInt)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsInt)]
[[play](https://go.dev/play/p/eFoIHbgzl-z)]
- **<big>IsIntStr</big>** : 验证字符串是否是可以转换为整数。 - **<big>IsIntStr</big>** : 验证字符串是否是可以转换为整数。
[[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)] [[doc](https://github.com/duke-git/lancet/blob/main/docs/validator_zh-CN.md#IsIntStr)]
[[play](https://go.dev/play/p/jQRtFv-a0Rk)] [[play](https://go.dev/play/p/jQRtFv-a0Rk)]

View File

@@ -43,8 +43,10 @@ import (
- [EqualWith](#EqualWith) - [EqualWith](#EqualWith)
- [Every](#Every) - [Every](#Every)
- [Filter](#Filter) - [Filter](#Filter)
- [Find](#Find) - [Find<sup>deprecated</sup>](#Find)
- [FindLast](#FindLast) - [FindBy](#FindBy)
- [FindLast<sup>deprecated</sup>](#FindLast)
- [FindLastBy](#FindLastBy)
- [Flatten](#Flatten) - [Flatten](#Flatten)
- [FlattenDeep](#FlattenDeep) - [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach) - [ForEach](#ForEach)
@@ -837,7 +839,7 @@ func main() {
} }
``` ```
### <span id="Find">Find</span> ### <span id="Find">Find(deprecated: use FindBy)</span>
<p>Iterates over elements of slice, returning the first one that passes a truth test on function.</p> <p>Iterates over elements of slice, returning the first one that passes a truth test on function.</p>
@@ -873,7 +875,43 @@ func main() {
} }
``` ```
### <span id="FindLast">FindLast</span> ### <span id="FindBy">FindBy</span>
<p>Iterates over elements of slice, returning the first one that passes a truth test on predicate function.If return T is nil or zero value then no items matched the predicate func. In contrast to Find or FindLast, its return value no longer requires dereferencing</p>
<b>Signature:</b>
```go
func FindBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result, ok := slice.FindBy(nums, isEven)
fmt.Println(result)
fmt.Println(ok)
// Output:
// 2
// true
}
```
### <span id="FindLast">FindLast(deprecated: use FindLastBy)</span>
<p>iterates over elements of slice from end to begin, returning the last one that passes a truth test on function.</p> <p>iterates over elements of slice from end to begin, returning the last one that passes a truth test on function.</p>
@@ -909,6 +947,42 @@ func main() {
} }
``` ```
### <span id="FindLastBy">FindLastBy</span>
<p>FindLastBy iterates over elements of slice, returning the last one that passes a truth test on predicate function. If return T is nil or zero value then no items matched the predicate func. In contrast to Find or FindLast, its return value no longer requires dereferencing</p>
<b>Signature:</b>
```go
func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result, ok := slice.FindLastBy(nums, isEven)
fmt.Println(result)
fmt.Println(ok)
// Output:
// 4
// true
}
```
### <span id="Flatten">Flatten</span> ### <span id="Flatten">Flatten</span>
<p>Flatten slice with one level.</p> <p>Flatten slice with one level.</p>

View File

@@ -43,8 +43,10 @@ import (
- [Equal](#Equal) - [Equal](#Equal)
- [EqualWith](#EqualWith) - [EqualWith](#EqualWith)
- [Filter](#Filter) - [Filter](#Filter)
- [Find](#Find) - [Find<sup>deprecated</sup>](#Find)
- [FindLast](#FindLast) - [FindBy](#FindBy)
- [FindLast<sup>deprecated</sup>](#FindLast)
- [FindLastBy](#FindLastBy)
- [Flatten](#Flatten) - [Flatten](#Flatten)
- [FlattenDeep](#FlattenDeep) - [FlattenDeep](#FlattenDeep)
- [ForEach](#ForEach) - [ForEach](#ForEach)
@@ -838,9 +840,9 @@ func main() {
} }
``` ```
### <span id="Find">Find</span> ### <span id="Find">Find (废弃:使用 FindBy)</span>
<p>遍历切片的元素返回第一个通过predicate函数真值测试的元素</p> <p>遍历slice的元素返回第一个通过predicate函数真值测试的元素</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -874,9 +876,45 @@ func main() {
} }
``` ```
### <span id="FindLast">FindLast</span> ### <span id="FindBy">FindBy</span>
<p>从头到尾遍历slice的元素返回最后一个通过predicate函数真值测试的元素</p> <p>遍历slice的元素返回一个通过predicate函数真值测试的元素</p>
<b>函数签名:</b>
```go
func FindBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result, ok := slice.FindBy(nums, isEven)
fmt.Println(result)
fmt.Println(ok)
// Output:
// 2
// true
}
```
### <span id="FindLast">FindLast(废弃:使用 FindLastBy)</span>
<p>遍历slice的元素返回最后一个通过predicate函数真值测试的元素。</p>
<b>函数签名:</b> <b>函数签名:</b>
@@ -910,6 +948,42 @@ func main() {
} }
``` ```
### <span id="FindLastBy">FindLastBy</span>
<p>从遍历slice的元素返回最后一个通过predicate函数真值测试的元素。</p>
<b>函数签名:</b>
```go
func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/slice"
)
func main() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result, ok := slice.FindLastBy(nums, isEven)
fmt.Println(result)
fmt.Println(ok)
// Output:
// 4
// true
}
```
### <span id="Flatten">Flatten</span> ### <span id="Flatten">Flatten</span>
<p>将切片压平一层</p> <p>将切片压平一层</p>

View File

@@ -46,6 +46,12 @@ import (
- [SplitWords](#SplitWords) - [SplitWords](#SplitWords)
- [WordCount](#WordCount) - [WordCount](#WordCount)
- [RemoveNonPrintable](#RemoveNonPrintable) - [RemoveNonPrintable](#RemoveNonPrintable)
- [StringToBytes](#StringToBytes)
- [BytesToString](#BytesToString)
- [IsBlank](#IsBlank)
- [HasPrefixAny](#HasPrefixAny)
- [HasSuffixAny](#HasSuffixAny)
- [IndexOffset](#IndexOffset)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -852,7 +858,6 @@ func main() {
} }
``` ```
### <span id="SplitWords">SplitWords</span> ### <span id="SplitWords">SplitWords</span>
<p>Splits a string into words, word only contains alphabetic characters.</p> <p>Splits a string into words, word only contains alphabetic characters.</p>
@@ -896,7 +901,6 @@ func main() {
} }
``` ```
### <span id="WordCount">WordCount</span> ### <span id="WordCount">WordCount</span>
<p>Return the number of meaningful word, word only contains alphabetic characters.</p> <p>Return the number of meaningful word, word only contains alphabetic characters.</p>
@@ -940,7 +944,6 @@ func main() {
} }
``` ```
### <span id="RemoveNonPrintable">RemoveNonPrintable</span> ### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
<p>Remove non-printable characters from a string.</p> <p>Remove non-printable characters from a string.</p>
@@ -969,4 +972,196 @@ func main() {
// hello world // hello world
// 你好😄 // 你好😄
} }
``` ```
### <span id="StringToBytes">StringToBytes</span>
<p>Converts a string to byte slice without a memory allocation.</p>
<b>Signature:</b>
```go
func StringToBytes(str string) (b []byte)
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.StringToBytes("abc")
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
}
```
### <span id="BytesToString">BytesToString</span>
<p>Converts a byte slice to string without a memory allocation.</p>
<b>Signature:</b>
```go
func BytesToString(bytes []byte) string
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
bytes := []byte{'a', 'b', 'c'}
result := strutil.BytesToString(bytes)
fmt.Println(result)
// Output:
// abc
}
```
### <span id="IsBlank">IsBlank</span>
<p>Checks if a string is whitespace or empty.</p>
<b>Signature:</b>
```go
func IsBlank(str string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.IsBlank("")
result2 := strutil.IsBlank("\t\v\f\n")
result3 := strutil.IsBlank(" 中文")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
```
### <span id="HasPrefixAny">HasPrefixAny</span>
<p>Checks if a string starts with any of an array of specified strings.</p>
<b>Signature:</b>
```go
func HasPrefixAny(str string, prefixes []string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="HasSuffixAny">HasSuffixAny</span>
<p>Checks if a string ends with any of an array of specified strings.</p>
<b>Signature:</b>
```go
func HasSuffixAny(str string, suffixes []string) bool
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="IndexOffset">IndexOffset</span>
<p>Returns the index of the first instance of substr in string after offsetting the string by `idxFrom`, or -1 if substr is not present in string.</p>
<b>Signature:</b>
```go
func IndexOffset(str string, substr string, idxFrom int) int
```
<b>Example:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
str := "foo bar hello world"
result1 := strutil.IndexOffset(str, "o", 5)
result2 := strutil.IndexOffset(str, "o", 0)
result3 := strutil.IndexOffset(str, "d", len(str)-1)
result4 := strutil.IndexOffset(str, "d", len(str))
result5 := strutil.IndexOffset(str, "f", -1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
}
```

View File

@@ -46,6 +46,12 @@ import (
- [SplitWords](#SplitWords) - [SplitWords](#SplitWords)
- [WordCount](#WordCount) - [WordCount](#WordCount)
- [RemoveNonPrintable](#RemoveNonPrintable) - [RemoveNonPrintable](#RemoveNonPrintable)
- [StringToBytes](#StringToBytes)
- [BytesToString](#BytesToString)
- [IsBlank](#IsBlank)
- [HasPrefixAny](#HasPrefixAny)
- [HasSuffixAny](#HasSuffixAny)
- [IndexOffset](#IndexOffset)
<div STYLE="page-break-after: always;"></div> <div STYLE="page-break-after: always;"></div>
@@ -895,7 +901,6 @@ func main() {
} }
``` ```
### <span id="WordCount">WordCount</span> ### <span id="WordCount">WordCount</span>
<p>返回有意义单词的数量,只支持字母字符单词。</p> <p>返回有意义单词的数量,只支持字母字符单词。</p>
@@ -939,7 +944,6 @@ func main() {
} }
``` ```
### <span id="RemoveNonPrintable">RemoveNonPrintable</span> ### <span id="RemoveNonPrintable">RemoveNonPrintable</span>
<p>删除字符串中不可打印的字符。</p> <p>删除字符串中不可打印的字符。</p>
@@ -968,4 +972,196 @@ func main() {
// hello world // hello world
// 你好😄 // 你好😄
} }
``` ```
### <span id="StringToBytes">StringToBytes</span>
<p>在不分配内存的情况下将字符串转换为字节片。</p>
<b>函数签名:</b>
```go
func StringToBytes(str string) (b []byte)
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.StringToBytes("abc")
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
}
```
### <span id="BytesToString">BytesToString</span>
<p>在不分配内存的情况下将字节切片转换为字符串。</p>
<b>函数签名:</b>
```go
func BytesToString(bytes []byte) string
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
bytes := []byte{'a', 'b', 'c'}
result := strutil.BytesToString(bytes)
fmt.Println(result)
// Output:
// abc
}
```
### <span id="IsBlank">IsBlank</span>
<p>检查字符串是否为空格或空。</p>
<b>函数签名:</b>
```go
func IsBlank(str string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.IsBlank("")
result2 := strutil.IsBlank("\t\v\f\n")
result3 := strutil.IsBlank(" 中文")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
```
### <span id="HasPrefixAny">HasPrefixAny</span>
<p>检查字符串是否以指定字符串数组中的任何一个开头。</p>
<b>函数签名:</b>
```go
func HasPrefixAny(str string, prefixes []string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
result2 := strutil.HasPrefixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="HasSuffixAny">HasSuffixAny</span>
<p>检查字符串是否以指定字符串数组中的任何一个结尾。</p>
<b>函数签名:</b>
```go
func HasSuffixAny(str string, suffixes []string) bool
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
result1 := strutil.HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
result2 := strutil.HasSuffixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
```
### <span id="IndexOffset">IndexOffset</span>
<p>将字符串偏移idxFrom后返回字符串中第一个 substr 实例的索引,如果字符串中不存在 substr则返回 -1。</p>
<b>函数签名:</b>
```go
func IndexOffset(str string, substr string, idxFrom int) int
```
<b>示例:</b>
```go
import (
"fmt"
"github.com/duke-git/lancet/v2/strutil"
)
func main() {
str := "foo bar hello world"
result1 := strutil.IndexOffset(str, "o", 5)
result2 := strutil.IndexOffset(str, "o", 0)
result3 := strutil.IndexOffset(str, "d", len(str)-1)
result4 := strutil.IndexOffset(str, "d", len(str))
result5 := strutil.IndexOffset(str, "f", -1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
}
```

View File

@@ -239,14 +239,17 @@ func main() {
} }
``` ```
### <span id="ExecCommand">CompareOsEnv</span> ### <span id="ExecCommand">ExecCommand</span>
<p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p> <p>Execute shell command, return the stdout and stderr string of command, and error if error occur. param `command` is a complete command string, like, ls -a (linux), dir(windows), ping 127.0.0.1. In linux, use /bin/bash -c to execute command, In windows, use powershell.exe to execute command.</p>
<b>Signature:</b> <b>Signature:</b>
```go ```go
func ExecCommand(command string) (stdout, stderr string, err error) type (
Option func(*exec.Cmd)
)
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
``` ```
<b>Example:</b> <b>Example:</b>

View File

@@ -246,7 +246,10 @@ func main() {
<b>Signature:</b> <b>Signature:</b>
```go ```go
func ExecCommand(command string) (stdout, stderr string, err error) type (
Option func(*exec.Cmd)
)
func ExecCommand(command string, opts ...Option) (stdout, stderr string, err error)
``` ```
<b>Example:</b> <b>Example:</b>

View File

@@ -348,7 +348,7 @@ func MiMeType(file any) string {
} }
// CurrentPath return current absolute path. // CurrentPath return current absolute path.
// Play: todo // Play: https://go.dev/play/p/s74a9iBGcSw
func CurrentPath() string { func CurrentPath() string {
var absPath string var absPath string
_, filename, _, ok := runtime.Caller(1) _, filename, _, ok := runtime.Caller(1)

View File

@@ -82,7 +82,7 @@ var (
// DecimalBytes returns a human readable byte size under decimal standard (base 1000) // DecimalBytes returns a human readable byte size under decimal standard (base 1000)
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4. // The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
// Play: todo // Play: https://go.dev/play/p/FPXs1suwRcs
func DecimalBytes(size float64, precision ...int) string { func DecimalBytes(size float64, precision ...int) string {
p := 5 p := 5
if len(precision) > 0 { if len(precision) > 0 {
@@ -95,7 +95,7 @@ func DecimalBytes(size float64, precision ...int) string {
// BinaryBytes returns a human-readable byte size under binary standard (base 1024) // BinaryBytes returns a human-readable byte size under binary standard (base 1024)
// The precision parameter specifies the number of digits after the decimal point, which defaults to 4. // The precision parameter specifies the number of digits after the decimal point, which defaults to 4.
// Play: todo // Play: https://go.dev/play/p/G9oHHMCAZxP
func BinaryBytes(size float64, precision ...int) string { func BinaryBytes(size float64, precision ...int) string {
p := 5 p := 5
if len(precision) > 0 { if len(precision) > 0 {
@@ -118,14 +118,14 @@ func calculateByteSize(size float64, base float64, byteUnits []string) (float64,
// ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000). // ParseDecimalBytes return the human readable bytes size string into the amount it represents(base 1000).
// ParseDecimalBytes("42 MB") -> 42000000, nil // ParseDecimalBytes("42 MB") -> 42000000, nil
// Play: todo // Play: https://go.dev/play/p/Am98ybWjvjj
func ParseDecimalBytes(size string) (uint64, error) { func ParseDecimalBytes(size string) (uint64, error) {
return parseBytes(size, "decimal") return parseBytes(size, "decimal")
} }
// ParseBinaryBytes return the human readable bytes size string into the amount it represents(base 1024). // ParseBinaryBytes return the human readable bytes size string into the amount it represents(base 1024).
// ParseBinaryBytes("42 mib") -> 44040192, nil // ParseBinaryBytes("42 mib") -> 44040192, nil
// Play: todo // Play: https://go.dev/play/p/69v1tTT62x8
func ParseBinaryBytes(size string) (uint64, error) { func ParseBinaryBytes(size string) (uint64, error) {
return parseBytes(size, "binary") return parseBytes(size, "binary")
} }

View File

@@ -48,14 +48,14 @@ func Comma[T constraints.Float | constraints.Integer | string](value T, symbol s
} }
// Pretty data to JSON string. // Pretty data to JSON string.
// Play: todo // Play: https://go.dev/play/p/YsciGj3FH2x
func Pretty(v any) (string, error) { func Pretty(v any) (string, error) {
out, err := json.MarshalIndent(v, "", " ") out, err := json.MarshalIndent(v, "", " ")
return string(out), err return string(out), err
} }
// PrettyToWriter pretty encode data to writer. // PrettyToWriter pretty encode data to writer.
// Play: todo // Play: https://go.dev/play/p/LPLZ3lDi5ma
func PrettyToWriter(v any, out io.Writer) error { func PrettyToWriter(v any, out io.Writer) error {
enc := json.NewEncoder(out) enc := json.NewEncoder(out)
enc.SetIndent("", " ") enc.SetIndent("", " ")

2
go.mod
View File

@@ -4,5 +4,5 @@ go 1.18
require ( require (
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a golang.org/x/exp v0.0.0-20221208152030-732eee02a75a
golang.org/x/text v0.5.0 golang.org/x/text v0.9.0
) )

2
go.sum
View File

@@ -2,3 +2,5 @@ golang.org/x/exp v0.0.0-20221208152030-732eee02a75a h1:4iLhBPcpqFmylhnkbY3W0ONLU
golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/exp v0.0.0-20221208152030-732eee02a75a/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=

View File

@@ -60,6 +60,7 @@ var _ = func() struct{} {
log.Println(dist) log.Println(dist)
*/ */
// Play: https://go.dev/play/p/4K7KBEPgS5M
func MapTo(src any, dst any) error { func MapTo(src any, dst any) error {
dstRef := reflect.ValueOf(dst) dstRef := reflect.ValueOf(dst)

View File

@@ -319,7 +319,27 @@ func GroupWith[T any, U comparable](slice []T, iteratee func(item T) U) map[U][]
// Find iterates over elements of slice, returning the first one that passes a truth test on predicate function. // Find iterates over elements of slice, returning the first one that passes a truth test on predicate function.
// If return T is nil then no items matched the predicate func. // If return T is nil then no items matched the predicate func.
// Play: https://go.dev/play/p/CBKeBoHVLgq // Play: https://go.dev/play/p/CBKeBoHVLgq
// Deprecated
func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) { func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
v, ok := FindBy(slice, predicate)
return &v, ok
}
// FindLast iterates over elements of slice from end to begin,
// return the first one that passes a truth test on predicate function.
// If return T is nil then no items matched the predicate func.
// Play: https://go.dev/play/p/FFDPV_j7URd
// Deprecated
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
v, ok := FindLastBy(slice, predicate)
return &v, ok
}
// FindBy iterates over elements of slice, returning the first one that passes a truth test on predicate function.
// If return T is nil or zero value then no items matched the predicate func.
// In contrast to Find or FindLast, its return value no longer requires dereferencing
// Play: todo
func FindBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool) {
index := -1 index := -1
for i, v := range slice { for i, v := range slice {
@@ -330,17 +350,17 @@ func Find[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) {
} }
if index == -1 { if index == -1 {
return nil, false return v, false
} }
return &slice[index], true return slice[index], true
} }
// FindLast iterates over elements of slice from end to begin, // FindLastBy iterates over elements of slice, returning the last one that passes a truth test on predicate function.
// return the first one that passes a truth test on predicate function. // If return T is nil or zero value then no items matched the predicate func.
// If return T is nil then no items matched the predicate func. // In contrast to Find or FindLast, its return value no longer requires dereferencing
// Play: https://go.dev/play/p/FFDPV_j7URd // Play: todo
func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, bool) { func FindLastBy[T any](slice []T, predicate func(index int, item T) bool) (v T, ok bool) {
index := -1 index := -1
for i := len(slice) - 1; i >= 0; i-- { for i := len(slice) - 1; i >= 0; i-- {
@@ -351,10 +371,10 @@ func FindLast[T any](slice []T, predicate func(index int, item T) bool) (*T, boo
} }
if index == -1 { if index == -1 {
return nil, false return v, false
} }
return &slice[index], true return slice[index], true
} }
// Flatten flattens slice with one level. // Flatten flattens slice with one level.
@@ -493,7 +513,7 @@ func Reduce[T any](slice []T, iteratee func(index int, item1, item2 T) T, initia
} }
// ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function. // ReduceBy produces a value from slice by accumulating the result of each element as passed through the reducer function.
// Play: todo // Play: https://go.dev/play/p/YKDpLi7gtee
func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U { func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U {
accumulator := initial accumulator := initial
@@ -505,7 +525,7 @@ func ReduceBy[T any, U any](slice []T, initial U, reducer func(index int, item T
} }
// ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left. // ReduceRight is like ReduceBy, but it iterates over elements of slice from right to left.
// Play: todo // Play: https://go.dev/play/p/qT9dZC03A1K
func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U { func ReduceRight[T any, U any](slice []T, initial U, reducer func(index int, item T, agg U) U) U {
accumulator := initial accumulator := initial

View File

@@ -341,6 +341,40 @@ func ExampleFindLast() {
// true // true
} }
func ExampleFindBy() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result, ok := FindBy(nums, isEven)
fmt.Println(result)
fmt.Println(ok)
// Output:
// 2
// true
}
func ExampleFindLastBy() {
nums := []int{1, 2, 3, 4, 5}
isEven := func(i, num int) bool {
return num%2 == 0
}
result, ok := FindLastBy(nums, isEven)
fmt.Println(result)
fmt.Println(ok)
// Output:
// 4
// true
}
func ExampleFlatten() { func ExampleFlatten() {
arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}} arrs := [][][]string{{{"a", "b"}}, {{"c", "d"}}}

View File

@@ -249,6 +249,44 @@ func TestFind(t *testing.T) {
assert.Equal(2, *res) assert.Equal(2, *res)
} }
func TestFindBy(t *testing.T) {
assert := internal.NewAssert(t, "TestFindBy")
nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool {
return num%2 == 0
}
res, ok := FindBy(nums, even)
if !ok {
t.Fatal("found nothing")
}
assert.Equal(2, res)
res, ok = FindBy(nums, func(_ int, v int) bool {
return v == 6
})
assert.Equal(res == 0 && ok == false, true)
}
func TestFindLastBy(t *testing.T) {
assert := internal.NewAssert(t, "TestFindBy")
nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool {
return num%2 == 0
}
res, ok := FindLastBy(nums, even)
if !ok {
t.Fatal("found nothing")
}
assert.Equal(4, res)
res, ok = FindLastBy(nums, func(_ int, v int) bool {
return v == 6
})
assert.Equal(res == 0 && ok == false, true)
}
func TestFindLast(t *testing.T) { func TestFindLast(t *testing.T) {
nums := []int{1, 2, 3, 4, 5} nums := []int{1, 2, 3, 4, 5}
even := func(i, num int) bool { even := func(i, num int) bool {

View File

@@ -4,9 +4,11 @@
package strutil package strutil
import ( import (
"reflect"
"strings" "strings"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
"unsafe"
) )
// CamelCase coverts string to camelCase string. Non letters and numbers will be ignored. // CamelCase coverts string to camelCase string. Non letters and numbers will be ignored.
@@ -373,3 +375,73 @@ func RemoveNonPrintable(str string) string {
return result return result
} }
// StringToBytes converts a string to byte slice without a memory allocation.
// Play: todo
func StringToBytes(str string) (b []byte) {
sh := *(*reflect.StringHeader)(unsafe.Pointer(&str))
bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
bh.Data, bh.Len, bh.Cap = sh.Data, sh.Len, sh.Len
return b
}
// BytesToString converts a byte slice to string without a memory allocation.
// Play: todo
func BytesToString(bytes []byte) string {
return *(*string)(unsafe.Pointer(&bytes))
}
// IsBlank checks if a string is whitespace, empty.
// Play: todo
func IsBlank(str string) bool {
if len(str) == 0 {
return true
}
// memory copies will occur here, but UTF8 will be compatible
runes := []rune(str)
for _, r := range runes {
if !unicode.IsSpace(r) {
return false
}
}
return true
}
// HasPrefixAny check if a string starts with any of an array of specified strings.
// Play: todo
func HasPrefixAny(str string, prefixes []string) bool {
if len(str) == 0 || len(prefixes) == 0 {
return false
}
for _, prefix := range prefixes {
if strings.HasPrefix(str, prefix) {
return true
}
}
return false
}
// HasSuffixAny check if a string ends with any of an array of specified strings.
// Play: todo
func HasSuffixAny(str string, suffixes []string) bool {
if len(str) == 0 || len(suffixes) == 0 {
return false
}
for _, suffix := range suffixes {
if strings.HasSuffix(str, suffix) {
return true
}
}
return false
}
// IndexOffset returns the index of the first instance of substr in string after offsetting the string by `idxFrom`,
// or -1 if substr is not present in string.
// Play: todo
func IndexOffset(str string, substr string, idxFrom int) int {
if idxFrom > len(str)-1 || idxFrom < 0 {
return -1
}
return strings.Index(str[idxFrom:], substr) + idxFrom
}

View File

@@ -2,6 +2,7 @@ package strutil
import ( import (
"fmt" "fmt"
"reflect"
) )
func ExampleAfter() { func ExampleAfter() {
@@ -449,3 +450,81 @@ func ExampleRemoveNonPrintable() {
// hello world // hello world
// 你好😄 // 你好😄
} }
func ExampleStringToBytes() {
result1 := StringToBytes("abc")
result2 := reflect.DeepEqual(result1, []byte{'a', 'b', 'c'})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// [97 98 99]
// true
}
func ExampleBytesToString() {
bytes := []byte{'a', 'b', 'c'}
result := BytesToString(bytes)
fmt.Println(result)
// Output:
// abc
}
func ExampleIsBlank() {
result1 := IsBlank("")
result2 := IsBlank("\t\v\f\n")
result3 := IsBlank(" 中文")
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
// Output:
// true
// true
// false
}
func ExampleHasPrefixAny() {
result1 := HasPrefixAny("foo bar", []string{"fo", "xyz", "hello"})
result2 := HasPrefixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleHasSuffixAny() {
result1 := HasSuffixAny("foo bar", []string{"bar", "xyz", "hello"})
result2 := HasSuffixAny("foo bar", []string{"oom", "world"})
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}
func ExampleIndexOffset() {
str := "foo bar hello world"
result1 := IndexOffset(str, "o", 5)
result2 := IndexOffset(str, "o", 0)
result3 := IndexOffset(str, "d", len(str)-1)
result4 := IndexOffset(str, "d", len(str))
result5 := IndexOffset(str, "f", -1)
fmt.Println(result1)
fmt.Println(result2)
fmt.Println(result3)
fmt.Println(result4)
fmt.Println(result5)
// Output:
// 12
// 1
// 18
// -1
// -1
}

View File

@@ -1,6 +1,7 @@
package strutil package strutil
import ( import (
"reflect"
"testing" "testing"
"github.com/duke-git/lancet/v2/internal" "github.com/duke-git/lancet/v2/internal"
@@ -349,3 +350,52 @@ func TestRemoveNonPrintable(t *testing.T) {
assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n")) assert.Equal("hello world", RemoveNonPrintable("hello\u00a0 \u200bworld\n"))
assert.Equal("你好😄", RemoveNonPrintable("你好😄")) assert.Equal("你好😄", RemoveNonPrintable("你好😄"))
} }
func TestStringToBytes(t *testing.T) {
assert := internal.NewAssert(t, "TestStringToBytes")
str := "abc"
bytes := StringToBytes(str)
assert.Equal(reflect.DeepEqual(bytes, []byte{'a', 'b', 'c'}), true)
}
func TestBytesToString(t *testing.T) {
assert := internal.NewAssert(t, "TestBytesToString")
bytes := []byte{'a', 'b', 'c'}
str := BytesToString(bytes)
assert.Equal(str == "abc", true)
}
func TestIsBlank(t *testing.T) {
assert := internal.NewAssert(t, "TestIsBlank")
assert.Equal(IsBlank(""), true)
assert.Equal(IsBlank("\t\v\f\n"), true)
assert.Equal(IsBlank(" 中文"), false)
}
func TestHasPrefixAny(t *testing.T) {
assert := internal.NewAssert(t, "TestHasPrefixAny")
str := "foo bar"
prefixes := []string{"fo", "xyz", "hello"}
notMatches := []string{"oom", "world"}
assert.Equal(HasPrefixAny(str, prefixes), true)
assert.Equal(HasPrefixAny(str, notMatches), false)
}
func TestHasSuffixAny(t *testing.T) {
assert := internal.NewAssert(t, "TestHasSuffixAny")
str := "foo bar"
suffixes := []string{"bar", "xyz", "hello"}
notMatches := []string{"oom", "world"}
assert.Equal(HasSuffixAny(str, suffixes), true)
assert.Equal(HasSuffixAny(str, notMatches), false)
}
func TestIndexOffset(t *testing.T) {
assert := internal.NewAssert(t, "TestIndexOffset")
str := "foo bar hello world"
assert.Equal(IndexOffset(str, "o", 5), 12)
assert.Equal(IndexOffset(str, "o", 0), 1)
assert.Equal(IndexOffset(str, "d", len(str)-1), len(str)-1)
assert.Equal(IndexOffset(str, "d", len(str)), -1)
assert.Equal(IndexOffset(str, "f", -1), -1)
}

26
system/os_darwin.go Normal file
View File

@@ -0,0 +1,26 @@
//go:build darwin
package system
import (
"os/exec"
"syscall"
)
func WithForeground() Option {
return func(c *exec.Cmd) {
if c.SysProcAttr == nil {
c.SysProcAttr = &syscall.SysProcAttr{
Foreground: true,
}
} else {
c.SysProcAttr.Foreground = true
}
}
}
func WithWinHide() Option {
return func(c *exec.Cmd) {
}
}

View File

@@ -1,3 +1,5 @@
//go:build linux
package system package system
import ( import (
@@ -16,3 +18,9 @@ func WithForeground() Option {
} }
} }
} }
func WithWinHide() Option {
return func(c *exec.Cmd) {
}
}

View File

@@ -1,3 +1,5 @@
//go:build windows
package system package system
import ( import (

View File

@@ -371,13 +371,13 @@ func IsGBK(data []byte) bool {
} }
// IsNumberStr check if the value is number(integer, float) or not. // IsNumberStr check if the value is number(integer, float) or not.
// Play: todo // Play: https://go.dev/play/p/mdJHOAvtsvF
func IsNumber(v any) bool { func IsNumber(v any) bool {
return IsInt(v) || IsFloat(v) return IsInt(v) || IsFloat(v)
} }
// IsFloat check if the value is float(float32, float34) or not. // IsFloat check if the value is float(float32, float34) or not.
// Play: todo // Play: https://go.dev/play/p/vsyG-sxr99_Z
func IsFloat(v any) bool { func IsFloat(v any) bool {
switch v.(type) { switch v.(type) {
case float32, float64: case float32, float64:
@@ -387,7 +387,7 @@ func IsFloat(v any) bool {
} }
// IsInt check if the value is integer(int, unit) or not. // IsInt check if the value is integer(int, unit) or not.
// Play: todo // Play: https://go.dev/play/p/eFoIHbgzl-z
func IsInt(v any) bool { func IsInt(v any) bool {
switch v.(type) { switch v.(type) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr: case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr: