golang键盘布局智能纠错与替代建议插件库TySug的使用

Golang 键盘布局智能纠错与替代建议插件库 TySug 的使用

TySug 是一个键盘布局感知的替代单词建议器集合,可以作为库和 Web 服务使用。

shcool

主要支持用例是针对短流行词列表(如域名)帮助纠正拼写错误,这对于防止电子邮件地址中的拼写错误、检测垃圾邮件、网络钓鱼(Typosquatting)等非常有用。

快速开始

如果你已安装 Docker,可以快速运行:

docker run --rm -it dynom/tysug:latest

在另一个终端中运行:

curl -s "http://127.0.0.1:1337/list/domains" --data-binary '{"input": "gmail.co"}'

作为 Web 服务使用

Web 服务使用 Jaro-Winkler 算法计算相似度:

{
  "result": "gmail.com",
  "score": 0.9777777777777777,
  "exact_match": false
}

作为库使用

TySug 是一组独立的包,每个库都有详细的 README 说明。

基本用法

import "github.com/Dynom/TySug/finder"

referenceList := []string{"example", "amplifier", "ample"}
ts := finder.New(referenceList, finder.WithAlgorithm(myAlgorithm))

alt, score, exact := ts.Find("exampel")
// alt   = example
// score = 0.9714285714285714
// exact = false (不在我们的参考列表中完全匹配)

使用不同算法

如果你想使用不同的算法,只需将算法包装在 finder.Algorithm 兼容类型中并传递给 Finder。

可能的算法选择:

  • Levenshtein
  • Damerau-Levenshtein
  • LCS
  • q-gram
  • Cosine
  • Jaccard
  • Jaro / Jaro-Winkler
  • Smith-Waterman
  • Sift4

处理置信度

添加自己的算法时,需要自己处理"置信度"元素:

var someAlgorithm finder.AlgWrapper = func(a, b string) float64 {
    // 结果是达到相等所需的步骤数
    // 像 Jaro 这样的算法产生 0.0 到 1.0 之间的值
    score := someAlgorithm.CalculateDistance(a, b)
    
    // 找到最长的字符串
    var ml = len(b)
    if len(a) >= len(b) {
        ml = len(a)
    }
    
    // 这会引入偏差。较长的输入比较短的输入略有优势,导致删除的权重较小。
    return 1 - (score / float64(ml))
}

sug := finder.New([]list, finder.WithAlgorithm(someAlgorithm))
bestMatch, score := sug.Find(input)
// 这里对于长度为 10 的字符串,有 2 个突变,分数可能是 0.8

示例

查找常见电子邮件域名拼写错误

func SuggestAlternative(email string, domains []string) (string, float64) {
    i := strings.LastIndex(email, "@")
    if 0 >= i || i >= len(email) {
        return email, 0
    }

    // 提取本地部分和域名部分
    localPart := email[:i]
    hostname := email[i+1:]

    sug, _ := finder.New(domains)
    alternative, score, exact := sug.Find(hostname)

    if exact || score > 0.9 {
        combined := localPart + "@" + alternative
        return combined, score
    }

    return email, score
}

参考列表

参考列表是包含已知/批准单词的列表。TySug 的 Web 服务未针对处理大型列表进行优化,而是针对"有主见的"列表。

键盘布局感知

TySug 的 Web 服务具有键盘布局感知能力。这意味着当输入是 ‘bee5’ 且参考列表包含单词 ‘beer’ 和 ‘beek’ 时,在 Query-US 键盘上会优先选择 ‘beer’。

拼写错误类型

处理拼写错误很复杂且高度依赖于上下文:

  • 原子拼写错误 - 输入一个(上下文)不正确但拼写正确的单词
  • 故意拼写错误 - 输入 “teh” 而不是 “the”
  • 标记拼写错误 - 故意的"拼写错误"

贡献指南

在贡献之前,请创建一个问题描述你想要贡献的内容。任何贡献都必须以 PR 的形式提供,并且 CI 构建必须通过。


更多关于golang键盘布局智能纠错与替代建议插件库TySug的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang键盘布局智能纠错与替代建议插件库TySug的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang键盘布局智能纠错与替代建议插件库TySug使用指南

TySug是一个用于Golang的键盘布局感知的字符串相似度计算和智能纠错库,它能够根据常见的键盘布局(如QWERTY、AZERTY等)提供拼写纠正和替代建议。

主要特性

  • 键盘布局感知的字符串相似度计算
  • 拼写错误检测与纠正
  • 提供替代建议列表
  • 支持自定义键盘布局
  • 轻量级且易于集成

安装

go get github.com/Dynom/TySug

基本使用示例

package main

import (
	"fmt"
	"github.com/Dynom/TySug/finder"
)

func main() {
	// 准备参考列表(字典)
	referenceList := []string{"apple", "banana", "orange", "pear", "peach"}

	// 创建查找器实例
	f := finder.New(referenceList, finder.WithAlgorithm(finder.AlgorithmTySug))

	// 测试拼写错误的输入
	testCases := []string{"appl3", "bannna", "oramge", "pear", "peahc"}

	for _, input := range testCases {
		suggestions, _ := f.Find(input)
		fmt.Printf("Input: %s -> Best match: %s\n", input, suggestions.Top())
	}
}

高级功能

1. 自定义键盘布局

package main

import (
	"fmt"
	"github.com/Dynom/TySug/finder"
	"github.com/Dynom/TySug/keyboard"
)

func main() {
	// 自定义键盘布局
	customLayout := keyboard.QwertyUS.Layout()
	// 修改布局,例如将'z'和'y'交换(德语键盘)
	customLayout['z'], customLayout['y'] = customLayout['y'], customLayout['z']

	// 使用自定义布局创建查找器
	f := finder.New(
		[]string{"apple", "banana", "orange"},
		finder.WithAlgorithm(finder.AlgorithmTySug),
		finder.WithKeyboardLayout(customLayout),
	)

	result, _ := f.Find("appze") // 在修改后的布局中,'z'接近'y'
	fmt.Println(result.Top())    // 可能输出 "apple"
}

2. 获取多个建议

package main

import (
	"fmt"
	"github.com/Dynom/TySug/finder"
)

func main() {
	f := finder.New([]string{"hello", "world", "golang", "good", "google"})

	// 获取前3个建议
	input := "goo"
	suggestions, _ := f.Find(input, finder.WithLimit(3))

	fmt.Printf("Suggestions for '%s':\n", input)
	for i, sug := range suggestions {
		fmt.Printf("%d. %s (score: %.2f)\n", i+1, sug.Term, sug.Score)
	}
}

3. 结合其他算法

package main

import (
	"fmt"
	"github.com/Dynom/TySug/finder"
	"github.com/Dynom/TySug/algorithm"
)

func main() {
	// 创建自定义算法组合
	comboAlgo := algorithm.NewCombo().
		AddAlgorithm(algorithm.NewJaroWinkler()).
		AddAlgorithm(algorithm.NewLevenshtein())

	f := finder.New(
		[]string{"algorithm", "function", "variable", "constant"},
		finder.WithAlgorithm(comboAlgo),
	)

	input := "functon"
	suggestion, _ := f.Find(input)
	fmt.Printf("Did you mean '%s' instead of '%s'?\n", suggestion.Top(), input)
}

实际应用场景

1. 搜索建议

package main

import (
	"fmt"
	"github.com/Dynom/TySug/finder"
)

type SearchService struct {
	finder *finder.Instance
}

func NewSearchService(products []string) *SearchService {
	return &SearchService{
		finder: finder.New(products, finder.WithAlgorithm(finder.AlgorithmTySug)),
	}
}

func (s *SearchService) GetSearchSuggestions(query string) []string {
	result, err := s.finder.Find(query, finder.WithLimit(5))
	if err != nil {
		return nil
	}

	var suggestions []string
	for _, sug := range result {
		suggestions = append(suggestions, sug.Term)
	}
	return suggestions
}

func main() {
	products := []string{"iPhone", "MacBook", "iPad", "iMac", "Apple Watch"}
	service := NewSearchService(products)

	fmt.Println(service.GetSearchSuggestions("iPhonr"))  // [iPhone iPad iMac]
	fmt.Println(service.GetSearchSuggestions("MakBook")) // [MacBook]
}

2. 表单输入验证

package main

import (
	"fmt"
	"github.com/Dynom/TySug/finder"
)

var countryFinder *finder.Instance

func init() {
	countries := []string{"United States", "Canada", "Mexico", "Brazil", "Germany"}
	countryFinder = finder.New(countries, finder.WithAlgorithm(finder.AlgorithmTySug))
}

func ValidateCountryInput(input string) (string, bool) {
	suggestion, err := countryFinder.Find(input)
	if err != nil {
		return "", false
	}

	// 如果匹配分数高于阈值,则认为是正确的
	if suggestion.TopScore() > 0.8 {
		return suggestion.Top(), true
	}
	return "", false
}

func main() {
	input := "Unted States"
	if corrected, ok := ValidateCountryInput(input); ok {
		fmt.Printf("Did you mean: %s?\n", corrected)
	} else {
		fmt.Println("Country not recognized")
	}
}

性能优化技巧

  1. 预加载字典:在服务启动时加载参考列表,避免每次请求都重新初始化
  2. 限制建议数量:使用WithLimit选项限制返回的建议数量
  3. 缓存结果:对常见输入进行缓存
  4. 并行处理:对于大型字典,可以考虑并行处理
package main

import (
	"fmt"
	"sync"
	"github.com/Dynom/TySug/finder"
)

type CachedFinder struct {
	finder  *finder.Instance
	cache   map[string]finder.Suggestions
	mu      sync.RWMutex
}

func NewCachedFinder(reference []string) *CachedFinder {
	return &CachedFinder{
		finder: finder.New(reference),
		cache:  make(map[string]finder.Suggestions),
	}
}

func (c *CachedFinder) Find(input string) (finder.Suggestions, error) {
	c.mu.RLock()
	if cached, exists := c.cache[input]; exists {
		c.mu.RUnlock()
		return cached, nil
	}
	c.mu.RUnlock()

	result, err := c.finder.Find(input)
	if err != nil {
		return nil, err
	}

	c.mu.Lock()
	c.cache[input] = result
	c.mu.Unlock()

	return result, nil
}

func main() {
	cf := NewCachedFinder([]string{"apple", "banana", "orange"})
	result, _ := cf.Find("appel")
	fmt.Println(result.Top())
}

总结

TySug是一个功能强大且灵活的Golang库,特别适合需要处理用户输入纠正和建议的场景。通过键盘布局感知的算法,它能够更准确地检测和纠正拼写错误,特别是那些由于键盘按键相邻而导致的常见错误。

该库的模块化设计允许开发者根据需要自定义键盘布局、相似度算法和各种选项,使其能够适应各种不同的应用场景。无论是构建搜索引擎的自动建议功能,还是实现表单输入的智能验证,TySug都能提供有效的解决方案。

通过合理使用缓存和性能优化技巧,TySug可以轻松集成到高性能应用中,为用户提供流畅的拼写纠正体验。

回到顶部