
本文介绍如何利用 Go 的 regexp.FindAllString 方法,通过精心设计的正则表达式将字符串拆分为包含单词和原始分隔符的切片,实现“分割并保留分隔符”的效果。
本文介绍如何利用 go 的 `regexp.findallstring` 方法,通过精心设计的正则表达式将字符串拆分为包含单词和原始分隔符的切片,实现“分割并保留分隔符”的效果。
在 Go 中,标准库的 strings.Split 或 strings.FieldsFunc 无法直接保留分隔符;而 regexp.Split 默认会丢弃匹配到的分隔符。要实现题目中要求的 [Hello | ! | It's | , | ...] 这类结果(即每个单词和每个标点符号都作为独立元素保留在切片中),关键在于不“分割”,而是“提取”所有有意义的单元——即把整个字符串看作由两类模式交替组成的序列:单词(如 Hello、It's)和单个分隔符(如 !、,、$ 等)。
为此,我们构造一个“匹配全部有效片段”的正则表达式,而非用于分割的分隔符模式。推荐正则表达式如下:
`[A-Za-z']+|[*?()$.,!]`
该表达式含义清晰:
- [A-Za-z']+:匹配一个或多个字母(大小写)或撇号(支持 It's 这类带撇号的单词);
- |:逻辑“或”;
- [*?()$.,!]:匹配任意一个指定的标点符号(注意:括号 ()、星号 *、美元符 $ 在字符类中无需转义,因其处于 [] 内)。
然后使用 regexp.MustCompile(pattern).FindAllString(s, -1) 即可按顺序提取所有匹配项,天然保持原始位置与分隔符完整性。
完整示例代码:
package main
import (
"fmt"
"regexp"
)
func main() {
input := "Hello! It's, a? beautiful$ day* (today and tomorrow)."
// 定义匹配模式:单词 或 指定标点
re := regexp.MustCompile(`[A-Za-z']+|[*?()$.,!]`)
parts := re.FindAllString(input, -1)
fmt.Printf("%q\n", parts)
// 输出:["Hello" "!" "It's" "," "a" "?" "beautiful" "$" "day" "*" "(" "today" "and" "tomorrow" ")" "."]
}
⚠️ 注意事项:
- 若需支持更多单词字符(如中文、数字、连字符 -),请扩展左侧字符类,例如 [A-Za-z0-9\u4e00-\u9fa5'-]+;
- 若分隔符集动态变化或来自配置,建议预编译正则以提升性能(如示例所示用 regexp.MustCompile);
- 该方案本质是“全量匹配”,不依赖分割逻辑,因此天然规避了空字符串、首尾分隔符等边界问题;
- 如需严格区分“空白分隔”(如空格)是否保留,请在正则中显式添加 \s+ 分支并权衡语义(本例中空格被忽略,符合题设输出)。
总结:Go 中实现“保留分隔符的分割”,最佳实践不是 Split,而是 FindAllString + 合理的交替匹配模式。它简洁、高效、可控,且完全符合结构化文本解析的实际需求。











