docs: 补充 SortJoin 文档并更新版本至 v1.1.1 (by AI)
This commit is contained in:
parent
47a62a3c16
commit
8875212dba
@ -1,5 +1,10 @@
|
||||
# Changelog: @go/encoding
|
||||
|
||||
## [v1.1.1] - 2026-05-08
|
||||
|
||||
### Added
|
||||
- **文档补全**:在 README 中补充了 `SortJoin` 接口的详细说明,该接口用于 Map 或 Struct 的排序拼接(签名场景)。
|
||||
|
||||
## [v1.1.0] - 2026-05-06
|
||||
|
||||
### Added
|
||||
|
||||
@ -29,6 +29,11 @@
|
||||
- `func UnUrlEncode(data string) ([]byte, error)`
|
||||
- `func HtmlEscape(data []byte) string`
|
||||
- `func HtmlUnescape(data string) string`
|
||||
- `func Utf8Valid(data []byte) bool`
|
||||
|
||||
### 签名工具 (Signature Utils)
|
||||
- `func SortJoin(v any, separator, connector string, urlEncode bool) string`
|
||||
将 Map 或 Struct 转换为排序并拼接后的字符串。常用于生成签名原串。支持自动 URL 编码。
|
||||
|
||||
### 整数与自定义进制 (IntEncoder)
|
||||
- `func EncodeInt(u uint64) []byte`
|
||||
|
||||
3
TEST.md
3
TEST.md
@ -1,7 +1,7 @@
|
||||
# Test Report: @go/encoding
|
||||
|
||||
## 📋 测试概览
|
||||
- **测试时间**: 2026-05-06
|
||||
- **测试时间**: 2026-05-08
|
||||
- **测试环境**: darwin/amd64
|
||||
- **Go 版本**: 1.25.0
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
| `TestHex` | PASS | Hex 编解码往返一致性,配合 `cast.As` 消除摩擦测试。 |
|
||||
| `TestBase64` | PASS | Standard/URL Base64 编解码一致性,`Un...FromString` 补全测试。 |
|
||||
| `TestWebEncoding` | PASS | URL 编解码、HTML 转义反转义往返测试。 |
|
||||
| `TestSortJoin` | PASS | Map 与 Struct 的排序拼接测试,验证签名场景。 |
|
||||
| `TestUtf8` | PASS | UTF-8 校验逻辑测试。 |
|
||||
| `TestIntEncoder` | PASS | 包含正常编解码、FillInt 补齐、ExchangeInt 置换、HashInt 确定性测试。 |
|
||||
|
||||
|
||||
42
encoding.go
42
encoding.go
@ -5,7 +5,11 @@ import (
|
||||
"encoding/hex"
|
||||
"html"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"apigo.cc/go/cast"
|
||||
)
|
||||
|
||||
// Hex 将数据转换为 Hex 编码的字节切片
|
||||
@ -148,3 +152,41 @@ func HtmlUnescape(data string) string {
|
||||
func Utf8Valid(data []byte) bool {
|
||||
return utf8.Valid(data)
|
||||
}
|
||||
|
||||
// SortJoin 将 Map 或 Struct 转换为排序并拼接后的字符串 (常用于签名)
|
||||
func SortJoin(v any, separator, connector string, urlEncode bool) string {
|
||||
var m map[string]any
|
||||
if vm, ok := v.(map[string]any); ok {
|
||||
m = vm
|
||||
} else if v != nil {
|
||||
cast.Convert(&m, v)
|
||||
}
|
||||
|
||||
if len(m) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
var builder strings.Builder
|
||||
for i, k := range keys {
|
||||
if i > 0 {
|
||||
builder.WriteString(separator)
|
||||
}
|
||||
val := cast.String(m[k])
|
||||
if urlEncode {
|
||||
builder.WriteString(url.QueryEscape(k))
|
||||
builder.WriteString(connector)
|
||||
builder.WriteString(url.QueryEscape(val))
|
||||
} else {
|
||||
builder.WriteString(k)
|
||||
builder.WriteString(connector)
|
||||
builder.WriteString(val)
|
||||
}
|
||||
}
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
@ -103,3 +103,33 @@ func TestUtf8(t *testing.T) {
|
||||
t.Error("Invalid UTF-8 should fail")
|
||||
}
|
||||
}
|
||||
|
||||
// --- SortJoin ---
|
||||
func TestSortJoin(t *testing.T) {
|
||||
m := map[string]any{
|
||||
"B": 2,
|
||||
"A": 1,
|
||||
"C": "hello world",
|
||||
}
|
||||
|
||||
// Test Map
|
||||
res := encoding.SortJoin(m, "&", "=", true)
|
||||
expected := "A=1&B=2&C=hello+world"
|
||||
if res != expected {
|
||||
t.Errorf("SortJoin Map failed: expected %s, got %s", expected, res)
|
||||
}
|
||||
|
||||
// Test Struct
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
ID string
|
||||
}
|
||||
u := User{Name: "Alice", Age: 30, ID: "123"}
|
||||
resStruct := encoding.SortJoin(u, ";", ":", false)
|
||||
// Keys: age, name, ID. Sorted: ID, age, name
|
||||
expectedStruct := "ID:123;age:30;name:Alice"
|
||||
if resStruct != expectedStruct {
|
||||
t.Errorf("SortJoin Struct failed: expected %s, got %s", expectedStruct, resStruct)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user