Documentation
¶
Overview ¶
lines.go —— 行号标注(文本行 → 带 4 位宽行号前缀)。
sanitize.go —— 落盘文件名安全化(textutil 通用文本/标识处理)。
字符 bigram 集合 + Jaccard 相似度的近重复检测原语(沉淀自 heimdallr 挖掘管道)。 可解释、小文本下精确、零依赖;候选规模(百~千条)下直接比对足够快,不必上向量库。
Package textutil 文本处理公共函数。
Index ¶
- Constants
- func BigramSet(s string) map[string]bool
- func ChunkLines(s string, target, hard int) []string
- func ClampRuneBoundary(s string, n int) int
- func EstTokens(runes int) int
- func EstTokensCJK(s string) int
- func EstTokensCJKRunes(n int) int
- func EstTokensCJKRunesWithRatio(n int, r CJKRatio) int
- func EstTokensOf(s string) int
- func EstTokensWithRatio(s string, r CJKRatio) int
- func EstTokensWithRounding(s string, r CJKRatio, mode TokenRounding) int
- func FTS5Query(s string) string
- func FirstNonEmpty(vals ...string) string
- func FitCharsLimit(windowTokens, reserveTokens int) int
- func GlobMatch(pattern, path string) bool
- func Jaccard(a, b map[string]bool) float64
- func NearDuplicate(a, b string, threshold float64) bool
- func NumberLines(s string) string
- func RuneUnitsCJK(s string) int
- func SanitizeFileStem(s string) string
- func Similarity(a, b string) float64
- func SplitRunes(s string, n int) []string
- func StripCodeFence(s string) string
- func Tokens(s string) []string
- func TokensJoined(s string) string
- func TruncBytes(s string, budget int) (string, bool)
- func TruncEllipsis(s string, n int) string
- func TruncNote(s string, n int, note string) string
- func TruncRunes(s string, n int) (string, bool)
- func UnitsToTokensCJK(units int) int
- type CJKRatio
- type TokenRounding
Constants ¶
const FitInputNote = "输入超出模型窗口预算,已截断留痕"
FitInputNote 窗口预算截断的统一注记文案(llm.fitInput 与 llm/wrap 共用 单源——此前两处字面量漂移无编译期信号)。
const TokenCharDivisor = 3
TokenCharDivisor 字符→token 估算除数(与 ZCode ESTIMATED_TOKEN_CHAR_DIVISOR 同值——中英混合语料的经验系数;精确计量归 provider usage 回传)。
Variables ¶
This section is empty.
Functions ¶
func BigramSet ¶
BigramSet 字符 bigram 集合:小写化、去空白(空白差异不算差异); 单字文本也有指纹(该字本身)。 零值/空串返回非 nil 空集,调用方可直接 range。
func ChunkLines ¶
ChunkLines 按行边界把文本切成 ≤target(rune)的增量片:凑片不跨行 (markdown 表格/列表行保持完整,中途渲染不碎);超长单行在 hard 处硬切 (base64/长 URL 不设上限会把节奏拖成整行卡顿)。SplitAfter 语义保留行尾 换行——join(所有片) 严格等于原文(消费方按序归并即得全文,无需分隔符约定)。 target/hard<=0 取缺省(160/400);空白文本返回 nil。
func ClampRuneBoundary ¶
ClampRuneBoundary 把字节下标 n 回退到所在 UTF-8 字符的起始边界(切点落进 多字节字符中间时会产生非法 UTF-8——头尾切分场景先经此钳制)。n>=len(s) 返回 len(s);n<=0 返回 0。
func EstTokensCJK ¶
EstTokensCJK CJK 感知的 token 估算:Han/Hangul/Kana/全角形式计 2 单位, 其余计 1,tokens ≈ units/3 + 1(非空下限 1)。纯 rune 计数口径对中文系统性 低估(经验上中文 ≈ 1 字 0.67 token、英文 ≈ 4 字符 1 token)——中文为主的 文本(提示词/会话历史/报告)用本函数;精确计量仍归 provider usage 回传。
func EstTokensCJKRunes ¶
EstTokensCJKRunes 已知 rune 数且内容以 CJK 为主时的保守计量 (units=2n → tokens=2n/3+1)——compact 等已有 rune 计数中间量的调用方 复用 CJK 口径,免字符串物化。
func EstTokensCJKRunesWithRatio ¶ added in v0.6.0
EstTokensCJKRunesWithRatio 已知 rune 数且内容以 CJK 为主时的折算估算 (免字符串物化——compact 等调用方手里只有 rune 计数中间量)。
与 EstTokensCJKRunes 同口径:**按「全部字符都是 CJK」估算**。 文本实际以 ASCII 为主时这个值会偏大,调用方需自行判断是否适用。
非法系数回退到默认系数;n<=0 返回 0。
func EstTokensOf ¶
EstTokensOf 字符串 token 估算(rune 数 / TokenCharDivisor 向上取整)。
func EstTokensWithRatio ¶ added in v0.6.0
EstTokensWithRatio 用指定折算系数估算 token(逐段向上取整)。
折算口径见 CJKRatio 的说明;默认系数用 DefaultCJKRatio()。 空串返回 0;非空串至少 1。
func EstTokensWithRounding ¶ added in v0.6.0
func EstTokensWithRounding(s string, r CJKRatio, mode TokenRounding) int
EstTokensWithRounding 用指定折算系数与取整方向估算 token。
取整方向是**参数**而不是另开一个函数:两种口径下「哪个数才是这个文本的 token 数」是同一个问题的两个答案,分成两个函数只会逼调用方在两套命名之间猜。
空串返回 0;非空串至少 1。
func FTS5Query ¶ added in v0.6.0
FTS5Query 把文本切成词元并拼成 SQLite FTS5 安全的 MATCH 查询串。
每个词元加双引号后用空格连接:FTS5 的空格是隐式 AND,于是 "磁" "盘" = 同时含「磁」与「盘」,正是中文子串检索要的效果。
加引号是**安全边界**,不是装饰:FTS5 的 AND / OR / NOT / NEAR 是**裸词**才生效的 运算符,用户输入里的 NOT 会被当成「排除后面那个词」而不是「查 NOT 这个词」; 引号把它降回字面量。引号同样能让 `"`、`*`、`(` 之类不构成语法错误。
空串(或切不出词元的串)返回空串——空 MATCH 是 FTS5 的语法错误, 调用方应据此跳过查询而不是拼上去。
func FirstNonEmpty ¶
FirstNonEmpty 返回首个非空串(全空返回 "")。多候选回退语义单源 (模型/配置/平台字段逐级兜底的高频形态)。
func FitCharsLimit ¶
FitCharsLimit 模型窗口的 rune 预算:(窗口-预留)×3/2×0.9(CJK 感知系数 1.5 token/rune 上界——v0.12.1 起两处共用;×0.9 留 10% 余量)。窗口无效 或预留缺省(<=0 取 窗口/20)不可算时返回 0(调用方跳过拟合)。
func GlobMatch ¶
GlobMatch 极简 glob:支持 `**`(跨目录)与 `*`/`?`(单段)。 语义对齐 .gitignore 常见用法:`web/**` 匹配 web/ 下一切(不含 web 自身); `*.vue` 匹配任意目录下的 .vue;`?` 消耗一个 rune(多字节文件名安全)。
func NearDuplicate ¶
NearDuplicate 相似度 ≥ threshold 视为近重复。
func NumberLines ¶
NumberLines 逐行加 4 位宽行号前缀(" 1|")。 用途:给 agent 的文件内容原文加行号——无行号原文会逼模型凭空编造 file:line 证据;行号前缀必须先于任何截断。尾随换行不产生幽灵空行。
func SanitizeFileStem ¶
SanitizeFileStem 文件名安全化:标识串(owner/repo/number 等外部标识)里的 路径分隔与引用语法字符归一为 "-"。外部标识常含 "/"(GitLab 嵌套组)、"#"、 ":"(分支名)、甚至 ".."——未消毒直接拼进留档文件名会导致写入失败甚至 目录穿越。只处理文件名主干(不含扩展名),调用方自行拼接后缀。
func Similarity ¶
Similarity 两段文本的相似度 = 字符 bigram 集合的 Jaccard 系数 [0,1]。 全等短路(含双双归一为空的等价情形交给 BigramSet/Jaccard,不在此误判)。
func SplitRunes ¶
SplitRunes 按 rune 等分为 ≤n 字符的块(最后一块可不足)。 n<=0 返回整串单块。大文本分块送 LLM 的公共原语。
func StripCodeFence ¶
StripCodeFence 剥离 markdown 代码围栏(全仓**代码围栏**语义单一事实源: jsonrepair 宽容解析与快路径切片共用)。取**第一个** ``` 围栏块;无栅栏原样 TrimSpace 返回。多围栏块输出(模型补多段代码)语义为「取第一块」——与宽容 解析链一致。注意与 fence 包的「数据区围栏」(fence.Data,注入卫生面)是两个 正交概念:本函数处理 markdown ``` 栅栏,后者圈定不可信数据边界。
func Tokens ¶ added in v0.6.0
Tokens 把文本切成**检索用词元**。
切法:
- CJK 逐字成词元("磁盘" → "磁", "盘")——汉字/假名/谚文按单字切;
- 拉丁与数字按空白与标点切词("disk is" → "disk", "is"),**原样保留大小写**;
- 只产出**裸词元**:标点、运算符、引号一律丢弃。
为什么 CJK 要逐字:SQLite FTS5 的 unicode61 分词器把连续汉字算作**一个词元**, 于是索引里的「磁盘长期偏小」是一个词元、查询「磁盘」是另一个词元, 两者永不相等 → **0 命中**,而且是**静默**返回空集(用户看到的是「库里没有这条」)。 真实中文文本没有空格分词,用户查的就是子串。
语义边界(重要,别当成通用分词器用):
- 返回的是**词的合集**,不是连续子串。"磁盘" 与 "盘磁" 的词元集合相同, 但两者在原文里位置相反——本函数不保留位置信息,**分不出顺序**。
- **不支持短语检索**:"disk is" 会被当成两个词的合取(都含),而不是相邻短语。 将来要支持短语,至少得能拿到词元 → 原文下标的位置信息。
- 与 BigramSet / Similarity **并存、不互相替代**:bigram 是字符二元组, 两者在**判定阈值**上不等价(中文「已修复」vs「未修复」:词元口径 Jaccard=0.5,二元组口径≈0.33)——阈值是按词元口径标定的,换口径会翻转判定。
词元**不去重**(保留出现次数,TF 语义对调用方更有用)。
func TokensJoined ¶ added in v0.6.0
TokensJoined 把 Tokens 的结果用空格连接。
**索引用**:FTS5 的 unicode61 分词器按空白切词,所以入库前把文本切成 空格分隔的词元串再存,索引里才会是「磁 盘 长 期」这样一个个单字词元。 查询侧用 FTS5Query(不是本函数——查询串要额外防运算符)。
func TruncBytes ¶
TruncBytes 按字节预算截断(rune 对齐:预算落点切进多字节字符时回退到 RuneStart 边界,不产生非法 UTF-8 尾字节)。第二个返回值 = 是否真发生了 截断。budget<0 视为非法上限,按"全部截断"处理(返回空串),不 panic。 字节预算面的唯一原语(skill 清单降级/全文上限共用——此前各写一份回退逻辑)。
func TruncEllipsis ¶
TruncEllipsis 截断并追加省略号(列表/标题/事件载荷展示面统一语义)。 n<=0 返回省略号;无需截断时原样返回。
func TruncNote ¶
TruncNote 截断并追加中文注记后缀(截断留痕语义单源:超限截断的输出带 「…(注记)」尾巴,调用方/模型可感知截断发生)。无需截断时原样返回; 注记以「…(」开头自行拼接,调用方传纯文字(如 "超长行截断")。
func TruncRunes ¶
TruncRunes 按 rune 截断,避免多字节字符被腰斩产生非法 UTF-8。 第二个返回值 = 是否真发生了截断。 n<0 视为非法上限,按"全部截断"处理(返回空串),不 panic。
func UnitsToTokensCJK ¶
UnitsToTokensCJK 单位量 → token(units/3 向上取整,非空下限 1)。
Types ¶
type CJKRatio ¶ added in v0.6.0
type CJKRatio struct {
// CJKCharsPerToken CJK 字符数 / token(如 2 = CJK 每 2 字符 1 token)。
CJKCharsPerToken int
// ASCIICharsPerToken 其余字符数 / token(如 4 = ASCII 每 4 字符 1 token)。
ASCIICharsPerToken int
}
CJKRatio token 折算系数:多少字符折算成 1 个 token。
非法值(<=0)在计算时回退到 DefaultCJKRatio 对应项——除零是硬错误, 而「系数配错」是可预期的配置问题,不该让调用方拿 panic 兜。
func DefaultCJKRatio ¶ added in v0.6.0
func DefaultCJKRatio() CJKRatio
DefaultCJKRatio 默认折算系数:CJK 每 2 字符 1 token、ASCII 每 4 字符 1 token。
type TokenRounding ¶ added in v0.6.0
type TokenRounding int
TokenRounding 折算取整方向。
两种取整在**混合文本**上差系统性:把同类字符合并后再取整,会把每段的零头 一起吞掉——多段混合文本累加起来是成规模的低估,不是随机误差。
const ( // RoundingSegment 逐段向上取整(默认):按**连续同类字符游程**切段, // 每段各自向上取整后求和。 // // 「中a中a中a中a」在逐段口径下是 8 段(每段 1 字符)→ 8 token; // 合并口径下只有 3 token。差的正是那 5 个「半截 token」。 RoundingSegment TokenRounding = iota // RoundingTotal 总量向上取整:同类字符合计后各向上取整一次再求和。 RoundingTotal )