Documentation
¶
Overview ¶
Package stringx 提供常用的字符串操作工具函数。
包含字符串查找、过滤、截取、反转、大小写转换、多模式替换 (Replacer trie 最长匹配 / NewMask 敏感词遮罩)等功能。 所有函数均安全处理 UTF-8 编码的字符串。
Index ¶
- Variables
- func Contains(list []string, str string) bool
- func ContainsAny(text string, keywords ...string) bool
- func Filter(s string, filter func(r rune) bool) string
- func FirstN(s string, n int, ellipsis ...string) string
- func FormatTemplate(template string, vars map[string]any) string
- func GenerateID() string
- func HasEmpty(args ...string) bool
- func IndentText(text, prefix string) string
- func Join(sep byte, elem ...string) string
- func JoinByComma(str []string) string
- func JoinWith(elem []string, sep string) string
- func NotEmpty(args ...string) bool
- func Pluralize(count int, word string) string
- func Remove(list []string, strs ...string) []string
- func Reverse(s string) string
- func SplitByComma(str string) []string
- func SplitCSVNonEmpty(s string) []string
- func SplitWith(str string, sep []string) []string
- func Substr(str string, start, stop int) (string, error)
- func TakeOne(valid, or string) string
- func TakeWithPriority(fns ...func() string) string
- func ToCamelCase(s string) string
- func TruncBytes(s string, budget int) (string, bool)
- func TruncEllipsis(s string, n int) string
- func TruncRunes(s string, n int) (string, bool)
- func Union(first, second []string) []string
- type Masker
- type Replacer
- type Rule
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrInvalidStartPosition indicates the start position is invalid. ErrInvalidStartPosition = errors.New("start position is invalid") // ErrInvalidStopPosition indicates the stop position is invalid. ErrInvalidStopPosition = errors.New("stop position is invalid") // ErrInvalidRange indicates the substring range is inverted (start > stop). ErrInvalidRange = errors.New("substring range is inverted") )
Functions ¶
func ContainsAny ¶
ContainsAny 检查 text 中是否包含 keywords 中的任意一个关键词(不区分大小写)。
用法:
stringx.ContainsAny("Security vulnerability found", "security", "vuln") // true
stringx.ContainsAny("normal text", "critical", "major") // false
func FormatTemplate ¶
FormatTemplate 用 vars 替换 template 里的 {key} 占位符。
模板语法: `{key}` 形式,key 在 vars 里查找。
- 未找到的 key 保留原 `{key}` 不替换(避免静默替换空字符串导致歧义)
- 嵌套 key 不支持(只 1 层)
- 业务场景: 错误信息模板("user {user_id} not found in tenant {tenant_id}") SQL 模板("SELECT * FROM users WHERE id = {id}"),log 模板
用法:
msg := stringx.FormatTemplate("user {user_id} not found", map[string]any{
"user_id": 42,
})
// → "user 42 not found"
注意: 这个函数不转义;如果业务需要把用户输入嵌入 SQL/HTML,先做 业务自己的转义/参数化(否则是注入漏洞)。
func GenerateID ¶
func GenerateID() string
GenerateID 生成基于时间戳的唯一 ID,格式: 20060102150405-<8位hex>。 适用于非严格唯一性要求的场景(如日志关联、临时标识)。 如需全局唯一,请使用 uuid。
func IndentText ¶
IndentText 为多行文本的第二行及之后每行添加缩进前缀。 第一行不缩进,适用于续行对齐场景。
用法:
stringx.IndentText("line1\nline2\nline3", " ")
// => "line1\n line2\n line3"
func Pluralize ¶
Pluralize 返回英文单词的复数形式。 规则:
- count == 1 → "1 word"
- 以 "y" 结尾且前一个字符为辅音 → 去 "y" 加 "ies" (story → stories)
- 以 "s", "sh", "ch", "x", "z" 结尾 → 加 "es" (box → boxes)
- 其他 → 加 "s" (file → files)
- word 为空 → "<count> "(计数仍然保留)
用法:
stringx.Pluralize(3, "file") // "3 files" stringx.Pluralize(1, "file") // "1 file" stringx.Pluralize(5, "story") // "5 stories"
func SplitCSVNonEmpty ¶ added in v0.22.0
SplitCSVNonEmpty 按逗号拆分字符串,逐项去掉首尾空白并丢弃空项。
与 SplitByComma 的区别:SplitByComma 就是 strings.Split(s, ",")——不 trim、 不过滤空项、空串返回 [""](1 个空元素),名字叫「按逗号拆」但实际把 「拆完顺手清干净」这层留给每个消费方各写一遍(典型样板:strings.Split → 逐项 TrimSpace → 跳过空项)。本原语把那层样板一次收进去。
与 SplitWith 的区别(不要拿 SplitWith 顶替):SplitWith 走 strings.Fields, 按**空白**切分,值里含空格时(如 glob 列表 "my glob")会被静默拆成两项, 改变语义。CSV 值的空白是有意义的("a b" 是一个值,不是两个),所以这条 面需要按逗号切的专门原语,而不是拿现有函数拼。
口径(写死在本函数契约里):
- 逐项去掉**首尾**空白(strings.TrimSpace,含 Unicode 空白);
- 去掉空白后为空的项**丢弃**("a,,b" → ["a","b"]);
- **空串返回 nil**(不是空切片)——调用方普遍用 != nil / len()>0 区分 「没配」与「配了空」,返回空切片会把两者混同;
- 全是空白或空项的输入(""、" "、",,")同样返回 nil。
用法:
stringx.SplitCSVNonEmpty("a, b,,c") // ["a" "b" "c"]
stringx.SplitCSVNonEmpty("a,,b") // ["a" "b"]
stringx.SplitCSVNonEmpty("") // nil
stringx.SplitCSVNonEmpty(" , ") // nil
func TakeWithPriority ¶
TakeWithPriority 返回第一个非空的函数返回值。
func ToCamelCase ¶
ToCamelCase 将字符串首字母转为小写。
按 rune 处理(多字节首字符不被截断)。非法 UTF-8 字节不 panic:range 会把 非法字节解成 U+FFFD,其**实际**宽度是 1 字节,而 utf8.RuneLen(U+FFFD) 是 3 ⇒ 此前用 RuneLen 切片会越界(slice bounds out of range [3:1])。
func TruncBytes ¶
TruncBytes 按字节预算截断(rune 对齐:预算落点切进多字节字符时回退到 RuneStart 边界,不产生非法 UTF-8 尾字节)。第二个返回值 = 是否真发生了 截断。budget<0 视为非法上限,按"全部截断"处理(返回空串),不 panic。
func TruncEllipsis ¶
TruncEllipsis 截断并追加省略号(列表/标题/事件载荷展示面统一语义)。 n<=0 返回省略号;无需截断时原样返回。
**n 的语义是「截断到 n 个 rune」,不含省略号**:返回值长度为 n(未截断)或 n+1(发生截断,省略号算 1 个 rune)。若调用方的 n 是"总长度预算" (如提交状态描述的 140 字符上限),本函数会超出预算 1 个字符——那种场景用 TruncRunes 自行拼接,或先按预算减 1 再调用。
func TruncRunes ¶
TruncRunes 按 rune 截断,避免多字节字符被腰斩产生非法 UTF-8。 第二个返回值 = 是否真发生了截断。n<0 视为非法上限,按"全部截断"处理 (返回空串),不 panic。
Types ¶
type Masker ¶ added in v0.16.0
type Masker struct {
// contains filtered or unexported fields
}
Masker 形态脱敏器。
构造后只读,可安全并发使用。
func NewMasker ¶ added in v0.16.0
NewMasker 创建形态脱敏器。
规则表由调用方完全提供,库不内置任何业务词表。返回 error 的情形:
- Re == nil;
- Name 为空;
- Name 重复(形态标签重复会让审计结果有歧义);
- Name 含定界符 '«' / '»' 或控制字符(输出将无法稳定解析);
- Keep 为负数。
规则表为空(nil)时返回可用的空脱敏器,Mask 原样返回输入。
Example ¶
rules := []Rule{
{Name: "kv-secret", Re: regexp.MustCompile(`token=([^\s]+)`), Keep: 2},
}
m, err := NewMasker(rules)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(m.Mask("call api with token=abcdef123456"))
Output: call api with to«kv-secret:****»56
type Replacer ¶ added in v0.7.0
type Replacer struct {
// contains filtered or unexported fields
}
Replacer 多模式字符串替换器。 与 strings.Replacer 的差异:按 rune 对齐匹配(不撕裂 UTF-8), 且同一起点恒取最长匹配。
func NewMask ¶ added in v0.7.0
NewMask 创建遮罩替换器:把 words 中每个词替换为等 rune 数的 mask 串。 用于敏感词遮罩场景,是 NewReplacer 的薄壳。
func NewReplacer ¶ added in v0.7.0
NewReplacer 创建多模式替换器:patterns[i] 命中的子串替换为 repls[i]。 两者长度必须一致;空 pattern 或 nil patterns(不替换任何词)的处理见 返回值。同名 pattern 后写覆盖先写。
type Rule ¶ added in v0.16.0
type Rule struct {
// Name 形态标签,如 "url-userinfo";会原样出现在掩码里供审计读。
// 不能为空、不能与同一规则表内其它规则的 Name 重复,也不能含定界符
// '«' / '»' 或控制字符(否则输出无法被稳定解析)。
Name string
// Re 匹配待脱敏内容的正则。命中的**整段**文本被替换为掩码
// (本库不区分捕获组,捕获组只影响匹配范围,不影响替换范围)。
// 为 nil 时 NewMasker 报错。零宽匹配(空匹配)会被忽略。
Re *regexp.Regexp
// Keep 掩码保留首尾各几个字符作定位线索;0 = 全掩。
// 语义是**封顶**:保留的字符数不随原值长度变化(见包内说明)。
//
// **命中长度不足 Keep*4 时整段全量打码(不做头尾保留)**——短值的头尾
// 保留会首尾相接覆盖整段原文,原值会完整留在输出里,掩码形同虚设。
// 调用方不必自己判断命中长度。
//
// 负数视为非法,NewMasker 报错。
Keep int
}
Rule 一条脱敏规则。
规则表由调用方完全提供,库不内置任何词表:Re 负责「按形态认出」待脱敏 内容,Name 是形态标签(会出现在掩码里供审计读),Keep 控制保留的定位 线索位数。