golang高效解析任意字符串、切片和无限缓冲区的分词插件库tokenizer的使用
Golang高效解析任意字符串、切片和无限缓冲区的分词插件库tokenizer的使用
Tokenizer是一个高性能的Golang库,用于解析任意字符串、切片和无限缓冲区为各种标记(tokens)。它具有以下主要特性:
主要特性
- 高性能
- 不使用正则表达式
- 提供简单API
- 支持整数和浮点数
- 支持带引号或其他"框架"的字符串
- 支持在带引号或"框架"字符串中的注入
- 支持Unicode
- 可自定义标记
- 自动检测空白符号
- 可解析任何数据语法(xml、json、yaml)和编程语言
- 单次数据遍历
- 可解析无限传入数据且不会panic
使用场景
- 解析html、xml、json、yaml等文本格式
- 解析大型或无限文本
- 解析任何编程语言
- 解析模板
- 解析公式
基本用法示例
解析SQL WHERE条件
import "github.com/bzick/tokenizer"
// 定义自定义标记键
const (
TEquality = iota + 1
TDot
TMath
TDoubleQuoted
)
// 配置tokenizer
parser := tokenizer.New()
parser.DefineTokens(TEquality, []string{"<", "<=", "==", ">=", ">", "!="})
parser.DefineTokens(TDot, []string{"."})
parser.DefineTokens(TMath, []string{"+", "-", "/", "*", "%"})
parser.DefineStringToken(TDoubleQuoted, `"`, `"`).SetEscapeSymbol(tokenizer.BackSlash)
parser.AllowKeywordSymbols(tokenizer.Underscore, tokenizer.Numbers)
// 创建标记流
stream := parser.ParseString(`user_id = 119 and modified > "2020-01-01 00:00:00" or amount >= 122.34`)
defer stream.Close()
// 遍历每个标记
for stream.IsValid() {
if stream.CurrentToken().Is(tokenizer.TokenKeyword) {
field := stream.CurrentToken().ValueString()
// ...
}
stream.GoNext()
}
解析结果
string: user_id = 119 and modified > "2020-01-01 00:00:00" or amount >= 122.34
tokens: |user_id| =| 119| and| modified| >| "2020-01-01 00:00:00"| or| amount| >=| 122.34|
| 0 | 1| 2 | 3 | 4 | 5| 6 | 7 | 8 | 9 | 10 |
0: {key: TokenKeyword, value: "user_id"} token.Value() == "user_id"
1: {key: TEquality, value: "="} token.Value() == "="
2: {key: TokenInteger, value: "119"} token.ValueInt64() == 119
3: {key: TokenKeyword, value: "and"} token.Value() == "and"
4: {key: TokenKeyword, value: "modified"} token.Value() == "modified"
5: {key: TEquality, value: ">"} token.Value() == ">"
6: {key: TokenString, value: "\"2020-01-01 00:00:00\""} token.ValueUnescaped() == "2020-01-01 00:00:00"
7: {key: TokenKeyword, value: "or"} token.Value() == "and"
8: {key: TokenKeyword, value: "amount"} token.Value() == "amount"
9: {key: TEquality, value: ">="} token.Value() == ">="
10: {key: TokenFloat, value: "122.34"} token.ValueFloat64() == 122.34
创建和解析
创建解析器
import "github.com/bzick/tokenizer"
var parser := tokenizer.New()
parser.AllowKeywordSymbols(tokenizer.Underscore, []rune{})
// ... 和其他配置代码
解析字符串或切片
有两种方式解析字符串或切片:
parser.ParseString(str)
parser.ParseBytes(slice)
解析无限流
fp, err := os.Open("data.json") // 大型JSON文件
// 检查文件系统,配置tokenizer...
stream := parser.ParseStream(fp, 4096).SetHistorySize(10)
defer stream.Close()
for stream.IsValid() {
// ...
stream.GoNext()
}
内置标记类型
tokenizer.TokenUnknown
- 未指定的标记键tokenizer.TokenKeyword
- 关键字,任何字母组合,包括Unicode字母tokenizer.TokenInteger
- 整数值tokenizer.TokenFloat
- 浮点/双精度值tokenizer.TokenString
- 带引号的字符串tokenizer.TokenStringFragment
- 框架(带引号)字符串的片段
完整示例
JSON解析器示例
const (
TokenCurlyOpen = 1
TokenCurlyClose = 2
TokenSquareOpen = 3
TokenSquareClose = 4
TokenColon = 5
TokenComma = 6
TokenDoubleQuoted = 7
)
// json解析器
parser := tokenizer.New()
parser.
DefineTokens(TokenCurlyOpen, []string{"{"}).
DefineTokens(TokenCurlyClose, []string{"}"}).
DefineTokens(TokenSquareOpen, []string{"["}).
DefineTokens(TokenSquareClose, []string{"]"}).
DefineTokens(TokenColon, []string{":"}).
DefineTokens(TokenComma, []string{","}).
DefineStringToken(TokenDoubleQuoted, `"`, `"`).SetSpecialSymbols(tokenizer.DefaultStringEscapes)
stream := parser.ParseString(`{"key": [1]}`)
带注入的框架字符串
const (
TokenOpenInjection = 1
TokenCloseInjection = 2
TokenQuotedString = 3
)
parser := tokenizer.New()
parser.DefineTokens(TokenOpenInjection, []string{"{{"})
parser.DefineTokens(TokenCloseInjection, []string{"}}"})
parser.DefineStringToken(TokenQuotedString, `"`, `"`).AddInjection(TokenOpenInjection, TokenCloseInjection)
parser.ParseString(`"one {{ two }} three"`)
性能基准
解析字符串/字节
pkg: tokenizer
cpu: Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
BenchmarkParseBytes
stream_test.go:251: Speed: 70 bytes string with 19.689µs: 3555284 byte/sec
stream_test.go:251: Speed: 7000 bytes string with 848.163µs: 8253130 byte/sec
stream_test.go:251: Speed: 700000 bytes string with 75.685945ms: 9248744 byte/sec
stream_test.go:251: Speed: 11093670 bytes string with 1.16611538s: 9513355 byte/sec
BenchmarkParseBytes-8 158481 7358 ns/op
解析无限流
pkg: tokenizer
cpu: Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
BenchmarkParseInfStream
stream_test.go:226: Speed: 70 bytes at 33.826µs: 2069414 byte/sec
stream_test.go:226: Speed: 7000 bytes at 627.357µs: 11157921 byte/sec
stream_test.go:226: Speed: 700000 bytes at 27.675799ms: 25292856 byte/sec
stream_test.go:226: Speed: 30316440 bytes at 1.18061702s: 25678471 byte/sec
BenchmarkParseInfStream-8 433092 2726 ns/op
PASS
已知问题
- 零字节
\x00
(\0
)会停止解析
更多关于golang高效解析任意字符串、切片和无限缓冲区的分词插件库tokenizer的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang高效解析任意字符串、切片和无限缓冲区的分词插件库tokenizer的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang高效分词插件库tokenizer使用指南
tokenizer是一个高效的Go语言分词库,支持任意字符串、切片和无限缓冲区的分词处理。下面我将详细介绍其使用方法并提供示例代码。
安装
go get github.com/sugarme/tokenizer
基本使用
1. 字符串分词
package main
import (
"fmt"
"github.com/sugarme/tokenizer"
)
func main() {
// 创建分词器实例
tk := tokenizer.NewTokenizer()
// 简单字符串分词
text := "Go语言高效分词库tokenizer"
tokens := tk.Tokenize(text)
fmt.Println("分词结果:")
for _, token := range tokens {
fmt.Printf("%s ", token)
}
// 输出: Go 语言 高效 分词 库 tokenizer
}
2. 切片分词
func sliceTokenization() {
tk := tokenizer.NewTokenizer()
// 字符串切片分词
texts := []string{"Go语言", "高效分词", "库tokenizer"}
fmt.Println("\n切片分词结果:")
for _, text := range texts {
tokens := tk.Tokenize(text)
for _, token := range tokens {
fmt.Printf("%s ", token)
}
fmt.Println()
}
/*
输出:
Go 语言
高效 分词
库 tokenizer
*/
}
高级功能
1. 自定义词典
func customDictionary() {
tk := tokenizer.NewTokenizer()
// 添加自定义词汇
tk.AddWord("Go语言", 10) // 10是词频权重
tk.AddWord("tokenizer", 10)
text := "Go语言高效分词库tokenizer"
tokens := tk.Tokenize(text)
fmt.Println("\n自定义词典分词结果:")
for _, token := range tokens {
fmt.Printf("%s ", token)
}
// 输出: Go语言 高效 分词 库 tokenizer
}
2. 处理无限缓冲区
func infiniteBuffer() {
tk := tokenizer.NewTokenizer()
// 模拟无限数据流
ch := make(chan string, 5)
ch <- "第一部分数据"
ch <- "第二部分数据"
ch <- "第三部分数据"
close(ch)
fmt.Println("\n流式分词结果:")
for text := range ch {
tokens := tk.Tokenize(text)
for _, token := range tokens {
fmt.Printf("%s ", token)
}
fmt.Println()
}
/*
输出:
第一 部分 数据
第二 部分 数据
第三 部分 数据
*/
}
3. 性能优化配置
func performanceOptimized() {
// 创建高性能分词器
config := tokenizer.Config{
NumThreads: 4, // 使用4个线程
BufferSize: 1024, // 缓冲区大小
DictPath: "dict.txt", // 自定义词典路径
}
tk, err := tokenizer.NewTokenizerWithConfig(config)
if err != nil {
panic(err)
}
// 大批量数据处理
largeText := make([]string, 1000)
for i := range largeText {
largeText[i] = fmt.Sprintf("文本数据%d", i)
}
results := make([][]string, len(largeText))
for i, text := range largeText {
results[i] = tk.Tokenize(text)
}
fmt.Println("\n性能优化分词示例完成")
}
实际应用示例
1. 搜索引擎分词
func searchEngineExample() {
tk := tokenizer.NewTokenizer()
query := "Go语言高性能网络编程"
tokens := tk.Tokenize(query)
fmt.Println("\n搜索查询分词:")
for _, token := range tokens {
fmt.Printf("%s ", token)
}
// 输出: Go 语言 高性能 网络 编程
}
2. 自然语言处理预处理
func nlpPreprocessing() {
tk := tokenizer.NewTokenizer()
// 添加NLP专用词汇
tk.AddWord("BERT", 10)
tk.AddWord("Transformer", 10)
text := "使用BERT和Transformer模型进行自然语言处理"
tokens := tk.Tokenize(text)
fmt.Println("\nNLP预处理分词:")
for _, token := range tokens {
fmt.Printf("%s ", token)
}
// 输出: 使用 BERT 和 Transformer 模型 进行 自然 语言 处理
}
总结
tokenizer库提供了以下主要优势:
- 支持多种输入类型(字符串、切片、流)
- 高性能分词处理
- 支持自定义词典
- 可配置的并发处理
- 简单的API接口
通过合理配置和使用,tokenizer可以满足从简单文本处理到大规模数据流分词的各种需求。