golang从字符串提取值并填充结构体的NLP解析插件nlp的使用

Golang 从字符串提取值并填充结构体的 NLP 解析插件 nlp 的使用

nlp 是一个通用的多语言自然语言处理器,它可以解析文本中的数据并返回填充好的模型。

支持的类型

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64
float32 float64
string
time.Time
time.Duration

安装

// 需要 go1.8+ 版本
go get -u github.com/shixzie/nlp

工作原理

RegisterModel(i interface{}, samples []string, ops …ModelOption) error

RegisterModel 接收 3 个参数:一个空结构体、一组样本和一些模型选项。

空结构体让 nlp 知道文本中所有可能的值,例如:

type Song struct {
    Name        string // 字段必须导出
    Artist      string
    ReleasedAt  time.Time
}
err := nl.RegisterModel(Song{}, someSamples, nlp.WithTimeFormat("2006"))
if err != nil {
    panic(err)
}
// ...

样本是 nlp 的关键部分,因为它们设置了关键字之间的"界限",同时也用于选择使用哪个模型来处理表达式。

样本必须有特殊的语法来设置这些"界限"和"关键字":

songSamples := []string{
    "play {Name} by {Artist}",
    "play {Name} from {Artist}",
    "play {Name}",
    "from {Artist} play {Name}",
    "play something from {ReleasedAt}",
}

Learn() error

Learn 使用 NaiveBayes 算法将所有模型样本映射到它们各自的模型。Learn() 还会训练所有已注册的模型,使它们能够适应未来的表达式。

// 必须在所有模型注册后调用,且在调用 nl.P() 之前调用
err := nl.Learn() 
if err != nil {
    panic(err)
}
// ...

P(expr string) interface{}

P 首先询问训练好的算法应该使用哪个模型,一旦我们获得了正确的且已经训练好的模型,我们就让它适应表达式。

使用示例

type Song struct {
    Name       string
    Artist     string
    ReleasedAt time.Time
}

songSamples := []string{
    "play {Name} by {Artist}",
    "play {Name} from {Artist}",
    "play {Name}",
    "from {Artist} play {Name}",
    "play something from {ReleasedAt}",
}

nl := nlp.New()
err := nl.RegisterModel(Song{}, songSamples, nlp.WithTimeFormat("2006"))
if err != nil {
    panic(err)
}

err = nl.Learn() // 必须在所有模型注册后调用,且在调用 P 之前
if err != nil {
    panic(err)
}

// 学习后可以多次调用 P
s := nl.P("hello sir can you pleeeeeease play King by Lauren Aquilina") 
if song, ok := s.(*Song); ok {
    fmt.Println("Success")
    fmt.Printf("%#v\n", song)
} else {
    fmt.Println("Failed")
}

// 输出:
//
// Success
// &main.Song{Name: "King", Artist: "Lauren Aquilina"}

更多关于golang从字符串提取值并填充结构体的NLP解析插件nlp的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang从字符串提取值并填充结构体的NLP解析插件nlp的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang 从字符串提取值并填充结构体的 NLP 解析插件

在 Go 语言中,我们可以使用 NLP (自然语言处理) 技术从非结构化文本中提取结构化数据并填充到结构体中。以下是几种常见方法和示例代码:

1. 使用正则表达式提取

对于简单的文本模式匹配,可以使用正则表达式:

package main

import (
	"fmt"
	"regexp"
)

type Person struct {
	Name  string
	Age   int
	Email string
}

func main() {
	text := "姓名: 张三, 年龄: 30, 邮箱: zhangsan@example.com"
	
	reName := regexp.MustCompile(`姓名:\s*([^,]+)`)
	reAge := regexp.MustCompile(`年龄:\s*(\d+)`)
	reEmail := regexp.MustCompile(`邮箱:\s*([^\s]+)`)
	
	var person Person
	if matches := reName.FindStringSubmatch(text); len(matches) > 1 {
		person.Name = matches[1]
	}
	if matches := reAge.FindStringSubmatch(text); len(matches) > 1 {
		fmt.Sscanf(matches[1], "%d", &person.Age)
	}
	if matches := reEmail.FindStringSubmatch(text); len(matches) > 1 {
		person.Email = matches[1]
	}
	
	fmt.Printf("%+v\n", person)
}

2. 使用 NLP 库 - Prose

Prose 是一个轻量级的 Go 自然语言处理库:

package main

import (
	"fmt"
	"log"
	"github.com/jdkato/prose/v2"
)

type DocumentInfo struct {
	Entities []string
	People   []string
}

func extractWithProse(text string) DocumentInfo {
	doc, err := prose.NewDocument(text)
	if err != nil {
		log.Fatal(err)
	}

	var info DocumentInfo
	for _, ent := range doc.Entities() {
		info.Entities = append(info.Entities, ent.Text)
		if ent.Label == "PERSON" {
			info.People = append(info.People, ent.Text)
		}
	}
	return info
}

func main() {
	text := "苹果公司由史蒂夫·乔布斯、史蒂夫·沃兹尼亚克和罗纳德·韦恩创立于1976年4月1日。"
	result := extractWithProse(text)
	fmt.Printf("%+v\n", result)
}

3. 使用更高级的 NLP 库 - GoNLP

对于更复杂的 NLP 任务,可以使用 GoNLP:

package main

import (
	"fmt"
	"github.com/gonlp/conllu"
	"github.com/gonlp/morfeusz"
)

type SentenceAnalysis struct {
	Tokens    []string
	Lemmas    []string
	PosTags   []string
}

func analyzeSentence(text string) SentenceAnalysis {
	// 初始化 Morfeusz 分析器
	analyzer, err := morfeusz.New()
	if err != nil {
		panic(err)
	}
	defer analyzer.Close()

	// 分析句子
	segments := analyzer.Analyze(text)
	
	var result SentenceAnalysis
	for _, seg := range segments {
		result.Tokens = append(result.Tokens, seg.Form)
		result.Lemmas = append(result.Lemmas, seg.Lemma)
		result.PosTags = append(result.PosTags, seg.PosTag)
	}
	
	return result
}

func main() {
	text := "快速棕色狐狸跳过懒狗"
	result := analyzeSentence(text)
	fmt.Printf("%+v\n", result)
}

4. 使用 JSON/XML 标签自动映射

如果文本是半结构化的(如 JSON/XML),可以使用结构体标签:

package main

import (
	"encoding/json"
	"fmt"
	"strings"
)

type User struct {
	Username string `json:"username" xml:"username"`
	Level    int    `json:"level" xml:"level"`
	Active   bool   `json:"active" xml:"active"`
}

func main() {
	// 从JSON提取
	jsonText := `{"username": "user123", "level": 5, "active": true}`
	var userFromJSON User
	json.NewDecoder(strings.NewReader(jsonText)).Decode(&userFromJSON)
	fmt.Printf("From JSON: %+v\n", userFromJSON)

	// 从XML提取(需要添加encoding/xml导入)
	// xmlText := `<User><username>user123</username><level>5</level><active>true</active></User>`
	// var userFromXML User
	// xml.Unmarshal([]byte(xmlText), &userFromXML)
	// fmt.Printf("From XML: %+v\n", userFromXML)
}

5. 自定义解析器

对于特定领域的文本,可以创建自定义解析器:

package main

import (
	"fmt"
	"strconv"
	"strings"
)

type Product struct {
	ID       int
	Name     string
	Price    float64
	InStock  bool
}

func parseProduct(text string) (Product, error) {
	parts := strings.Split(text, "|")
	if len(parts) != 4 {
		return Product{}, fmt.Errorf("invalid product format")
	}

	var p Product
	var err error
	
	p.ID, err = strconv.Atoi(strings.TrimSpace(parts[0]))
	if err != nil {
		return Product{}, err
	}
	
	p.Name = strings.TrimSpace(parts[1])
	
	p.Price, err = strconv.ParseFloat(strings.TrimSpace(parts[2]), 64)
	if err != nil {
		return Product{}, err
	}
	
	p.InStock = strings.ToLower(strings.TrimSpace(parts[3])) == "true"
	
	return p, nil
}

func main() {
	text := "123 | 笔记本电脑 | 1299.99 | true"
	product, err := parseProduct(text)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Printf("%+v\n", product)
}

总结

  1. 对于简单模式,使用正则表达式是最快捷的方法
  2. 对于自然语言文本,可以使用 Prose 或 GoNLP 等 NLP 库
  3. 对于半结构化数据(JSON/XML),使用标准库的编码包
  4. 对于特定领域文本,创建自定义解析器通常是最佳选择

选择哪种方法取决于你的具体需求、文本的复杂程度以及性能要求。

回到顶部