rivo/uniseg
GitHub: rivo/uniseg
一个遵循 Unicode 标准的 Go 库,提供文本分段、自动换行和等宽字符串宽度计算功能。
Stars: 723 | Forks: 69
# Go 的 Unicode 文本分段
[](https://pkg.go.dev/github.com/rivo/uniseg)
[](https://goreportcard.com/report/github.com/rivo/uniseg)
这个 Go 包根据 [Unicode 标准附录 #29](https://unicode.org/reports/tr29/) 实现了 Unicode 文本分段,根据 [Unicode 标准附录 #14](https://unicode.org/reports/tr14/) (Unicode 版本 15.0.0)实现了 Unicode 换行,并实现了类似于 [wcwidth](https://man7.org/linux/man-pages/man3/wcwidth.3.html) 的等宽字体字符串宽度计算。
## 背景
### 字素簇
在 Go 中,[字符串是只读的字节切片](https://go.dev/blog/strings)。它们可以使用 `for` 循环或通过强制类型转换:`[]rune(str)` 转换为 Unicode 码位。然而,多个码位可能会被组合成一个用户感知到的字符,也就是 Unicode 规范中所说的“字素簇”。以下是一些示例:
|字符串|字节 (UTF-8)|码位|字素簇|
|-|-|-|-|
|Käse|6 个字节:`4b 61 cc 88 73 65`|5 个码位:`4b 61 308 73 65`|4 个字素簇:`[4b],[61 308],[73],[65]`|
|🏳️🌈|14 个字节:`f0 9f 8f b3 ef b8 8f e2 80 8d f0 9f 8c 88`|4 个码位:`1f3f3 fe0f 200d 1f308`|1 个字素簇:`[1f3f3 fe0f 200d 1f308]`|
|🇩🇪|8 个字节:`f0 9f 87 a9 f0 9f 87 aa`|2 个码位:`1f1e9 1f1ea`|1 个字素簇:`[1f1e9 1f1ea]`|
该包提供了遍历这些字素簇的工具。这可用于确定用户感知到的字符数量、在预期的位置拆分字符串,或提取组成一个单元的单个字符。
### 单词边界
单词边界被用于许多不同的场景中。最常见的是选择(双击鼠标选择)、光标移动(“移至下一个单词”的 Ctrl+方向键操作),以及用于搜索和替换的对话框选项“全字匹配”。它们也被用于数据库查询中,以确定元素之间是否在一定的单词数量范围内。搜索也可能使用单词边界来确定匹配的项目。该包提供了确定字符串中单词边界的工具。
### 句子边界
句子边界通常用于三击鼠标或其他一些方法来选择或遍历大于单个单词的文本块。它们也用于数据库查询中,以确定单词是否出现在同一个句子中。该包提供了确定字符串中句子边界的工具。
### 换行
换行,也称为自动换行,是将一段文本分割成多行的过程,以便它能适应页面、窗口或其他显示区域的可用宽度。该包提供了用于确定字符串可以在哪里换行、不能在哪里换行以及必须在哪里换行(例如在换行符之后)的工具。
### 等宽
大多数终端或使用等宽字体(例如源代码编辑器)的文本显示器/文本编辑器对每个字符使用固定的宽度。某些字符(例如 emoji 或亚洲及其他语言中发现的字符)可能会占据不止一个字符单元。该包提供了确定字符串在等宽字体下显示时将占据的单元数量的工具。有关更多信息,请参见[这里](https://pkg.go.dev/github.com/rivo/uniseg#hdr-Monospace_Width)。
## 安装
```
go get github.com/rivo/uniseg
```
## 示例
### 计算字符串中的字符数
```
n := uniseg.GraphemeClusterCount("🇩🇪🏳️🌈")
fmt.Println(n)
// 2
```
### 计算等宽字符串的宽度
```
width := uniseg.StringWidth("🇩🇪🏳️🌈!")
fmt.Println(width)
// 5
```
### 使用 [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) 类
这是遍历字素簇最便捷的方法:
```
gr := uniseg.NewGraphemes("👍🏼!")
for gr.Next() {
fmt.Printf("%x ", gr.Runes())
}
// [1f44d 1f3fc] [21]
```
### 使用 [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) 或 [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) 函数
这避免了分配新的 `Graphemes` 对象,但它需要手动处理状态和边界:
```
str := "🇩🇪🏳️🌈"
state := -1
var c string
for len(str) > 0 {
c, str, _, state = uniseg.StepString(str, state)
fmt.Printf("%x ", []rune(c))
}
// [1f1e9 1f1ea] [1f3f3 fe0f 200d 1f308]
```
### 进阶示例
[`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) 类提供了访问此包所有功能的最便捷方式。但在某些情况下,直接使用专门的函数可能会更好。例如,如果您只对单词分段感兴趣,请使用 [`FirstWord`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWord) 或 [`FirstWordInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstWordInString):
```
str := "Hello, world!"
state := -1
var c string
for len(str) > 0 {
c, str, state = uniseg.FirstWordInString(str, state)
fmt.Printf("(%s)\n", c)
}
// (Hello)
// (,)
// ( )
// (world)
// (!)
```
类似地,使用
- [`FirstGraphemeCluster`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeCluster) 或 [`FirstGraphemeClusterInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeClusterInString) 仅用于字素簇判定,
- [`FirstSentence`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentence) 或 [`FirstSentenceInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstSentenceInString) 仅用于句子分段,以及
- [`FirstLineSegment`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegment) 或 [`FirstLineSegmentInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstLineSegmentInString) 用于换行/自动换行(尽管首选使用 [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step) 或 [`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString),因为它会遵守字素簇的边界)。
如果您只对字符的宽度感兴趣,请使用 [`FirstGraphemeCluster`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeCluster) 或 [`FirstGraphemeClusterInString`](https://pkg.go.dev/github.com/rivo/uniseg#FirstGraphemeClusterInString)。它比使用 [`Step`](https://pkg.go.dev/github.com/rivo/uniseg#Step)、[`StepString`](https://pkg.go.dev/github.com/rivo/uniseg#StepString) 或 [`Graphemes`](https://pkg.go.dev/github.com/rivo/uniseg#Graphemes) 类快得多,因为它不包含处理单词/句子/行边界的逻辑。
最后,如果您需要在保留字素簇的同时反转字符串,请使用 [`ReverseString`](https://pkg.go.dev/github.com/rivo/uniseg#ReverseString):
```
fmt.Println(uniseg.ReverseString("🇩🇪🏳️🌈"))
// 🏳️🌈🇩🇪
```
## 文档
有关此包的文档,请参阅 https://pkg.go.dev/github.com/rivo/uniseg。
## 依赖
该包不依赖于标准库之外的任何包。
## 赞助此项目
在 GitHub 上[成为赞助者](https://github.com/sponsors/rivo?metadata_source=uniseg_readme)以支持此项目!
## 您的反馈
欢迎在此处的 GitHub 上添加您的 issue,最好在提交任何 PR 之前先提出。如果您有任何问题,请随时与我们联系。
标签:EVTX分析, Go, Ruby工具, Unicode, 基础库, 字符串处理, 日志审计