Go x/text/runes If 怎样组合不同字符处理规则
来源:17golang原创
时间:2026-10-27 05:32:11 153浏览 收藏
runes.If(set, tIn, tNotIn) 用字符集合选择两套转换规则:属于集合的连续 rune 片段交给 tIn,其余连续片段交给 tNotIn。任意分支传 nil 表示原样复制。它适合“这一类字符用规则甲,其他字符用规则乙”的文本任务;如果目的是让全部文本依次经过两套转换,应考虑串联组合。
官方地址:https://pkg.go.dev/golang.org/x/text/runes
按字符集合选择两套处理规则
以派生检索标签为例:要求将 ASCII 大写字母改为小写,将连字符和下划线改为空格,其他字符保留。这里有三个清楚的对象:用于分类的字符集合、大写字母的映射分支、处理其他字符的分支。先把它们写出来,比在一个很长的回调中混合业务条件更容易说明规则归属。
这个任务是对现有字符转换能力的用法介绍,不对应某次新版本发布。本文只处理这个有界的标签规则,不把它扩展成通用搜索归一化方案。

把分支规则写成可调用的转换函数
下面使用 Predicate 定义 A 到 Z 的集合,再把两套 Map 交给 If。函数每次创建自己的转换器,并在入口拒绝无效 UTF-8。返回的是检索用途的派生字符串,调用方仍可另外保存原始展示文本。
package textpolicy
import (
"fmt"
"unicode/utf8"
"golang.org/x/text/runes"
"golang.org/x/text/transform"
)
// SearchLabel 生成派生检索文本,只处理 ASCII 大写字母和指定分隔符。
func SearchLabel(input string) (string, error) {
if !utf8.ValidString(input) {
return "", fmt.Errorf("输入必须是有效的 UTF-8")
}
upperASCII := runes.Predicate(func(r rune) bool {
return r >= 'A' && r
项目需依赖 golang.org/x/text 模块,并按项目约束选择版本。根据代码规则,输入 API-中_A9 对应的预期文本是 api 中 a9:ASCII 大写变小写,两个分隔符变空格,中文和数字保持原样。这是规则推导,不是本机运行记录。
lower 中的加法只对 A 到 Z 成立,正确性依赖 upperASCII 的集合定义。以后若把集合扩大到全部 Unicode 字母,就不能保留这段算术映射;两部分需要一起修改。separators 对其他 rune 直接返回原值,也不会自动合并连续空格或去掉首尾空格。
理解连续片段和 Reset 的关系
If 按原始输入中是否属于集合来划分连续片段,而不是把每个 rune 都作为独立的一次完整转换。每个片段开始时,对应的子转换器会被 Reset。对于本例这种无状态的单字符映射,片段边界不会影响映射结果;但替换成依赖上下文的子转换器时,这条约定就很重要。
例如一个子转换器需要跨字符保存状态,就不能假设它的状态可以越过另一分支的片段继续积累。选择集合同时决定了允许它观察的片段范围。字符分类也不是词法分析:一个 rune 是否在 A 到 Z 内,并不能说明它属于某种完整标识符、单词或语言文本。

如果只是想让不匹配的字符保持原样,可将 tNotIn 设为 nil;集合内不处理则将 tIn 设为 nil。这表示使用复制行为,不表示删除片段。若需要删除字符,应明确选择删除规则。
区分条件选择与串联转换
| 需求 | 组合方式 | 要注意的差别 |
|---|---|---|
| 按集合选择一套规则 | runes.If | 分支选择基于输入字符分类 |
| 全部文本依次经过多个转换 | transform.Chain | 后面的转换接收前面的结果 |
| 简单地逐字符改写 | runes.Map | 一个映射函数可能已经足够 |
本例改成单个 Map 也能表达同样的字符替换。采用 If 的意义,是显式分离集合与两套可组合规则,而不是声称代码必然更短或更快。当每个分支都只是一个很短的条件时,单个 Map 可能更直接;当规则已有独立转换器时,If 的组合方式更有价值。
不要把 If 想成“先跑 tIn,再把转换后的结果送去判断 tNotIn”。分支不是串联。若业务需要先进行一次全局转换,再根据新字符分类,应把这个先后关系明确放在外层组合中。
保留输入约定和转换后的使用范围
本例的 utf8.ValidString 是业务入口约定。If 本身遇到无效 UTF-8 时,会用 RuneError 决定分支,但把原始非法字节交给相应子转换器;不能据此推断整个组合会统一拒绝非法数据。分支里的 Map 又有自己的非法输入处理语义,因此入口明确接受范围更容易解释。
transform.String 返回转换结果、已消费的源字节数和错误;没有错误时才把完整结果交给调用方。这里的 consumed 是字节数,不是 rune 数。若以后替换成可能报错的子转换器,示例仍会返回错误,不会把部分转换文本当成完整标签保存。
派生检索标签也不适合自动充当唯一标识。原始的 A-B 和 A_B 都会映射成 a b;这种合并是本例规则的结果,不能拿派生值替换数据库主键或需要保留原文差异的字段。
常见问题:nil 分支会删除字符吗?不会,表示复制。连续的大写字母会逐字重新初始化吗?If 按连续片段调用分支,不是每个字符各自建立一个片段。它能判断一个完整单词吗?单纯的 Set 只判断 rune。需要去重空格怎么办?应另行明确空格处理规则,不要把它当成当前示例已经包含的功能。
-
860 收藏
-
843 收藏
-
826 收藏
-
809 收藏
-
792 收藏
-
181 收藏
-
306 收藏
-
102 收藏
-
130 收藏
-
394 收藏
-
123 收藏
-
463 收藏
-
351 收藏
-
475 收藏
-
173 收藏
-
151 收藏
-
332 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习