提升正则表达式性能:全面解析Golang regexp/syntax包

news2024/11/24 0:05:36

提升正则表达式性能:全面解析Golang regexp/syntax包

    • 介绍
    • 基本概念
      • 正则表达式简介
      • `regexp/syntax`包的作用
    • `regexp/syntax`包的结构
      • 核心组件
      • 结构详解
        • Parser
        • Regexp
        • Op
        • Inst
        • Prog
    • 使用`Parser`解析正则表达式
      • 解析正则表达式
      • AST的结构
    • 分析解析后的正则表达式树
      • AST节点类型
      • 分析示例
    • 正则表达式的优化和重写
      • 优化正则表达式
      • 重写正则表达式
      • 优化示例
    • 编译正则表达式
      • 编译过程
      • 编译示例
    • 使用`regexp/syntax`进行自定义匹配
      • 自定义匹配逻辑
      • 自定义匹配示例
    • 常见问题与解决方案
      • 问题1:解析错误
      • 问题2:优化结果不符合预期
      • 问题3:编译错误
      • 问题4:匹配结果不正确
    • 实战案例
      • 案例描述
      • 实战步骤
      • 实战代码
    • 结论

在这里插入图片描述

介绍

在Go语言的标准库中,regexp包为开发者提供了强大的正则表达式支持。然而,对于一些高级用户来说,标准的正则表达式功能可能不够灵活。这时,regexp/syntax包便派上了用场。regexp/syntax包提供了对正则表达式的底层解析、分析和编译功能,让开发者可以更精细地控制和优化正则表达式的行为。

regexp/syntax包的主要用途包括:

  • 解析:将正则表达式解析为抽象语法树(AST)。
  • 分析:对解析后的AST进行分析,以了解其结构和行为。
  • 编译:将AST编译为高效的匹配代码,以执行正则匹配操作。
  • 优化和重写:对正则表达式进行优化和重写,以提高性能和可读性。

在实际开发中,regexp/syntax包适用于需要自定义正则表达式处理逻辑的场景,如编写自定义的正则表达式引擎、分析和优化复杂的正则表达式等。

本文将详细介绍regexp/syntax包的使用方法和技巧,包括解析、分析、优化和编译正则表达式,并通过实战案例展示其应用。

基本概念

在深入了解regexp/syntax包之前,我们需要先回顾一些正则表达式的基本概念。

正则表达式简介

正则表达式是一种用于匹配字符串模式的强大工具。在许多编程语言中,正则表达式用于查找、替换和验证字符串。正则表达式由一系列字符和元字符组成,用于描述字符串的匹配规则。

常见的正则表达式元素包括:

  • 字符:字母、数字、符号等,如a, 1, @
  • 字符集:用方括号括起来的一组字符,如[abc]表示匹配abc
  • 预定义字符集:如\d表示匹配任何数字,\w表示匹配任何字母或数字。
  • 量词:指定字符出现的次数,如*表示0次或多次,+表示1次或多次,?表示0次或1次。
  • 锚点:如^表示字符串的开头,$表示字符串的结尾。

regexp/syntax包的作用

regexp/syntax包提供了对正则表达式的底层解析和操作能力,使开发者可以深入理解和控制正则表达式的行为。具体来说,该包提供了以下功能:

  • 解析:将正则表达式字符串解析为抽象语法树(AST),以便进行进一步的分析和操作。
  • 分析:对解析后的AST进行分析,了解正则表达式的结构和匹配逻辑。
  • 编译:将AST编译为高效的匹配代码,以执行实际的正则表达式匹配操作。
  • 优化和重写:对正则表达式进行优化和重写,以提高性能和可读性。

接下来,我们将详细介绍regexp/syntax包的结构和使用方法。

regexp/syntax包的结构

regexp/syntax包包含多个用于解析和操作正则表达式的核心组件。在使用该包时,我们需要了解其主要组成部分和功能。

核心组件

  • Parser:解析器,用于将正则表达式字符串解析为抽象语法树(AST)。
  • Regexp:表示解析后的正则表达式AST,包括正则表达式的所有结构信息。
  • Op:操作码,表示正则表达式中的基本操作单元,如匹配字符、匹配字符集等。
  • Inst:指令,表示正则表达式的一个匹配步骤,由操作码和相关参数组成。
  • Prog:表示编译后的正则表达式程序,由一系列指令组成。

结构详解

Parser

Parserregexp/syntax包中的核心组件之一。它负责将正则表达式字符串解析为抽象语法树(AST)。Parser的使用方法如下:

package main

import (
	"fmt"
	"regexp/syntax"
)

func main() {
	expr := "a(b|c)*d"
	re, err := syntax.Parse(expr, syntax.Perl)
	if err != nil {
		fmt.Println("Error parsing expression:", err)
		return
	}
	fmt.Println("Parsed expression:", re)
}

上述代码中,syntax.Parse函数将正则表达式字符串expr解析为Regexp类型的AST。如果解析过程中出现错误,将返回相应的错误信息。

Regexp

Regexp类型表示解析后的正则表达式AST,包括正则表达式的所有结构信息。Regexp类型的结构如下:

type Regexp struct {
	Op       Op         // 操作码
	Flags    Flags      // 标志位
	Sub      []*Regexp  // 子表达式
	Sub0     [1]*Regexp // 内部缓存
	Min, Max int        // 重复次数
	Rune     []rune     // 匹配的字符
}

其中,Op表示正则表达式的操作码,Sub表示子表达式列表,MinMax表示重复次数,Rune表示匹配的字符列表。

Op

Op表示正则表达式中的基本操作单元,如匹配字符、匹配字符集等。常见的操作码包括:

  • OpLiteral:匹配一个字符或字符序列。
  • OpCharClass:匹配字符集。
  • OpStar:匹配0次或多次。
  • OpPlus:匹配1次或多次。
  • OpQuest:匹配0次或1次。
  • OpConcat:连接操作,用于连接多个子表达式。
  • OpAlternate:选择操作,用于选择多个子表达式中的一个。
Inst

Inst表示正则表达式的一个匹配步骤,由操作码和相关参数组成。Inst的结构如下:

type Inst struct {
	Op   InstOp  // 操作码
	Out  uint32  // 下一条指令的索引
	Arg  uint32  // 参数
	Rune []rune  // 匹配的字符
}

其中,Op表示指令的操作码,Out表示下一条指令的索引,Arg表示操作码的参数,Rune表示匹配的字符。

Prog

Prog表示编译后的正则表达式程序,由一系列指令组成。Prog的结构如下:

type Prog struct {
	Inst   []Inst // 指令列表
	Start  int    // 起始指令的索引
	NumCap int    // 捕获组的数量
}

其中,Inst表示指令列表,Start表示起始指令的索引,NumCap表示捕获组的数量。

了解了regexp/syntax包的结构后,接下来我们将介绍如何使用Parser解析正则表达式。

使用Parser解析正则表达式

regexp/syntax包中,Parser是一个非常重要的组件,它负责将正则表达式字符串解析为抽象语法树(AST)。通过解析正则表达式,我们可以获得其结构信息,便于后续的分析和处理。

解析正则表达式

要解析正则表达式字符串,可以使用syntax.Parse函数。该函数接受两个参数:正则表达式字符串和解析模式。常见的解析模式包括syntax.Perlsyntax.POSIX。下面是一个解析正则表达式的示例:

package main

import (
	"fmt"
	"regexp/syntax"
)

func main() {
	expr := "a(b|c)*d"
	re, err := syntax.Parse(expr, syntax.Perl)
	if err != nil {
		fmt.Println("Error parsing expression:", err)
		return
	}
	fmt.Println("Parsed expression:", re)
}

在上述代码中,我们首先定义了一个正则表达式字符串expr,然后使用syntax.Parse函数将其解析为Regexp类型的AST。如果解析过程中出现错误,将返回相应的错误信息。

AST的结构

解析后的Regexp类型的AST包含了正则表达式的所有结构信息。通过访问AST的各个字段,我们可以了解正则表达式的具体结构。例如:

func printRegexp(re *syntax.Regexp) {
	fmt.Println("Op:", re.Op)
	fmt.Println("Flags:", re.Flags)
	for _, sub := range re.Sub {
		printRegexp(sub)
	}
	fmt.Println("Min:", re.Min)
	fmt.Println("Max:", re.Max)
	fmt.Println("Rune:", re.Rune)
}

上述代码中,printRegexp函数递归地打印了Regexp类型AST的各个字段信息,包括操作码、标志位、子

表达式列表、重复次数和匹配的字符列表。

通过解析正则表达式并访问其AST结构,我们可以深入了解正则表达式的具体匹配逻辑和结构信息。这对于编写自定义的正则表达式处理逻辑非常有帮助。

分析解析后的正则表达式树

在解析正则表达式之后,我们可以对其AST进行分析,以了解其结构和匹配逻辑。这对于优化和调试正则表达式非常有用。

AST节点类型

regexp/syntax包中的AST节点类型由操作码Op表示。常见的操作码包括:

  • OpLiteral:匹配一个字符或字符序列。
  • OpCharClass:匹配字符集。
  • OpStar:匹配0次或多次。
  • OpPlus:匹配1次或多次。
  • OpQuest:匹配0次或1次。
  • OpConcat:连接操作,用于连接多个子表达式。
  • OpAlternate:选择操作,用于选择多个子表达式中的一个。

通过分析AST中的操作码,我们可以了解正则表达式的具体匹配逻辑。

分析示例

下面是一个分析解析后的正则表达式AST的示例代码:

package main

import (
	"fmt"
	"regexp/syntax"
)

func analyzeRegexp(re *syntax.Regexp) {
	switch re.Op {
	case syntax.OpLiteral:
		fmt.Println("Literal:", string(re.Rune))
	case syntax.OpCharClass:
		fmt.Println("CharClass:", re.Rune)
	case syntax.OpStar:
		fmt.Println("Star")
		analyzeRegexp(re.Sub[0])
	case syntax.OpPlus:
		fmt.Println("Plus")
		analyzeRegexp(re.Sub[0])
	case syntax.OpQuest:
		fmt.Println("Quest")
		analyzeRegexp(re.Sub[0])
	case syntax.OpConcat:
		fmt.Println("Concat")
		for _, sub := range re.Sub {
			analyzeRegexp(sub)
		}
	case syntax.OpAlternate:
		fmt.Println("Alternate")
		for _, sub := range re.Sub {
			analyzeRegexp(sub)
		}
	default:
		fmt.Println("Unknown Op:", re.Op)
	}
}

func main() {
	expr := "a(b|c)*d"
	re, err := syntax.Parse(expr, syntax.Perl)
	if err != nil {
		fmt.Println("Error parsing expression:", err)
		return
	}
	analyzeRegexp(re)
}

在上述代码中,analyzeRegexp函数根据AST节点的操作码Op,递归地分析和打印了正则表达式的结构信息。通过这种方式,我们可以了解正则表达式的具体匹配逻辑。

正则表达式的优化和重写

在使用正则表达式时,性能和可读性是两个重要的考虑因素。regexp/syntax包提供了一些工具和方法,帮助我们优化和重写正则表达式,以提高其性能和可读性。

优化正则表达式

优化正则表达式的目的是减少匹配操作的时间复杂度,从而提高性能。常见的优化策略包括:

  • 简化重复模式:将冗长的重复模式简化为更紧凑的形式。例如,将a{1,}简化为a+
  • 合并字符集:将多个单字符匹配合并为字符集。例如,将[aA]简化为[aA]
  • 消除冗余:去除正则表达式中的冗余部分。例如,将a|a简化为a

重写正则表达式

重写正则表达式的目的是提高其可读性,使其更易于理解和维护。常见的重写策略包括:

  • 使用命名捕获组:使用命名捕获组替代位置捕获组,提高可读性和可维护性。
  • 使用注释:在复杂的正则表达式中添加注释,解释其匹配逻辑。

优化示例

下面是一个使用regexp/syntax包优化正则表达式的示例代码:

package main

import (
	"fmt"
	"regexp/syntax"
)

func optimizeRegexp(re *syntax.Regexp) *syntax.Regexp {
	switch re.Op {
	case syntax.OpConcat:
		// 合并相邻的字符
		var newSub []*syntax.Regexp
		for _, sub := range re.Sub {
			if len(newSub) > 0 && sub.Op == syntax.OpLiteral && newSub[len(newSub)-1].Op == syntax.OpLiteral {
				// 合并相邻的OpLiteral
				newSub[len(newSub)-1].Rune = append(newSub[len(newSub)-1].Rune, sub.Rune...)
			} else {
				newSub = append(newSub, sub)
			}
		}
		re.Sub = newSub
	case syntax.OpAlternate:
		// 消除冗余选择
		uniqueSubs := map[string]*syntax.Regexp{}
		for _, sub := range re.Sub {
			uniqueSubs[sub.String()] = sub
		}
		var newSub []*syntax.Regexp
		for _, sub := range uniqueSubs {
			newSub = append(newSub, sub)
		}
		re.Sub = newSub
	}
	for i, sub := range re.Sub {
		re.Sub[i] = optimizeRegexp(sub)
	}
	return re
}

func main() {
	expr := "a|a|b|c"
	re, err := syntax.Parse(expr, syntax.Perl)
	if err != nil {
		fmt.Println("Error parsing expression:", err)
		return
	}
	fmt.Println("Original expression:", re)
	optimizedRe := optimizeRegexp(re)
	fmt.Println("Optimized expression:", optimizedRe)
}

在上述代码中,optimizeRegexp函数对正则表达式进行了优化,包括合并相邻的字符和消除冗余选择。通过这种方式,我们可以提高正则表达式的性能和可读性。

编译正则表达式

在解析和优化正则表达式之后,我们可以将其编译为高效的匹配代码。regexp/syntax包提供了相关的功能,帮助我们将正则表达式的AST编译为可执行的指令集。

编译过程

编译正则表达式的过程包括以下步骤:

  1. 解析:将正则表达式字符串解析为AST。
  2. 优化:对AST进行优化和重写,提高性能和可读性。
  3. 编译:将优化后的AST编译为指令集。

编译示例

下面是一个使用regexp/syntax包编译正则表达式的示例代码:

package main

import (
	"fmt"
	"regexp/syntax"
)

func compileRegexp(expr string) (*syntax.Prog, error) {
	// 解析正则表达式
	re, err := syntax.Parse(expr, syntax.Perl)
	if err != nil {
		return nil, fmt.Errorf("error parsing expression: %w", err)
	}

	// 优化正则表达式
	re = optimizeRegexp(re)

	// 编译正则表达式
	prog, err := syntax.Compile(re)
	if err != nil {
		return nil, fmt.Errorf("error compiling expression: %w", err)
	}
	return prog, nil
}

func main() {
	expr := "a(b|c)*d"
	prog, err := compileRegexp(expr)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Compiled program:", prog)
}

在上述代码中,compileRegexp函数首先解析正则表达式,然后对其进行优化,最后将优化后的AST编译为指令集。通过这种方式,我们可以获得高效的匹配代码,以执行正则匹配操作。

使用regexp/syntax进行自定义匹配

regexp/syntax包不仅可以解析和编译正则表达式,还可以帮助我们实现自定义的正则匹配逻辑。在某些高级应用场景中,我们可能需要对匹配过程进行细粒度的控制,以实现特定的匹配需求。

自定义匹配逻辑

自定义匹配逻辑的核心思想是利用regexp/syntax包提供的AST和指令集,手动控制匹配过程。通过分析指令集,我们可以实现自定义的匹配操作。

自定义匹配示例

下面是一个使用regexp/syntax包实现自定义匹配逻辑的示例代码:

package main

import (
	"fmt"
	"regexp/syntax"
)

func customMatch(prog *syntax.Prog, input string) bool {
	pc := 0
	sp := 0
	stack := []int{}

	for pc < len(prog.Inst) {
		inst := prog.Inst[pc]
		switch inst.Op {
		case syntax.InstFail:
			return false
		case syntax.InstAlt:
			stack = append(stack, pc+int(inst.Arg))
			pc = int(inst.Out)
		case syntax.InstAltMatch:
			if sp < len(input) && input[sp] == inst.Rune[0] {
				stack = append(stack, pc+int(inst.Arg))
				pc = int(inst.Out)
			} else {
				pc++
			}
		case syntax.InstRune:
			if sp < len(input) && input[sp] == inst.Rune[0] {
				sp++
				pc = int(inst.Out)
			} else {
				if len(stack) > 0 {
					pc = stack[len(stack)-1]
					stack = stack[:len(stack)-1]
				} else {
					return false
				}
			}
		case syntax.InstMatch:
			return true
		default:
			pc++
		}
	}
	return false
}

func main() {
	expr := "a(b|c)*d"
	prog, err := compileRegexp(expr)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	input := "abcbcd"
	match := customMatch(prog, input)
	fmt.Println("Match result:", match)
}

在上述代码中,customMatch函数通过手动控制指令集的执行,实现了自定义的正则匹配逻辑。通过这种方式,我们可以根据具体需求定制匹配过程。

常见问题与解决方案

在使用regexp/syntax包时,开发者可能会遇到一些常见的问题。下面列出了一些常见问题及其解决方案。

问题1:解析错误

描述:在解析正则表达式时,可能会遇到解析错误。

解决方案:检查正则表达式的语法是否正确,确保没有遗漏或错误的字符。例如:

expr := "(a|b"
_, err := syntax.Parse(expr, syntax.Perl)
if err != nil {
	fmt.Println("Error parsing expression:", err)
}

问题2:优化结果不符合预期

描述:优化后的正则表达式可能与预期不一致。

解决方案:检查优化逻辑是否正确,确保没有错误地删除或合并正则表达式的部分。例如:

re := &syntax.Regexp{
	Op: syntax.OpAlternate,
	Sub: []*syntax.Regexp{
		{Op: syntax.OpLiteral, Rune: []rune{'a'}},
		{Op: syntax.OpLiteral, Rune: []rune{'a'}},
	},
}
optimizedRe := optimizeRegexp(re)
fmt.Println("Optimized expression:", optimizedRe)

问题3:编译错误

描述:在编译正则表达式时,可能会遇到编译错误。

解决方案:检查正则表达式的语法和结构,确保其能够正确解析和优化。例如:

expr := "a(b|c)*d"
_, err := compileRegexp(expr)
if err !=

 nil {
	fmt.Println("Error compiling expression:", err)
}

问题4:匹配结果不正确

描述:自定义匹配逻辑的结果可能与预期不一致。

解决方案:检查自定义匹配逻辑,确保正确处理了所有指令和匹配情况。例如:

expr := "a(b|c)*d"
prog, err := compileRegexp(expr)
if err != nil {
	fmt.Println("Error:", err)
	return
}
input := "abcbcd"
match := customMatch(prog, input)
fmt.Println("Match result:", match)

实战案例

通过一个综合案例展示regexp/syntax包的应用,可以更好地理解其功能和使用方法。下面是一个使用regexp/syntax包实现自定义正则表达式引擎的实战案例。

案例描述

我们将实现一个简单的正则表达式引擎,用于匹配输入字符串中的特定模式。具体来说,我们将实现一个支持字母和数字匹配的引擎。

实战步骤

  1. 解析正则表达式:首先,我们将正则表达式字符串解析为AST。
  2. 优化正则表达式:然后,我们对AST进行优化,提高匹配性能。
  3. 编译正则表达式:接着,我们将优化后的AST编译为指令集。
  4. 自定义匹配逻辑:最后,我们实现自定义的匹配逻辑,匹配输入字符串。

实战代码

package main

import (
	"fmt"
	"regexp/syntax"
)

func main() {
	expr := "a(b|c)*d"
	input := "abcbcd"
	match, err := matchRegexp(expr, input)
	if err != nil {
		fmt.Println("Error:", err)
		return
	}
	fmt.Println("Match result:", match)
}

func matchRegexp(expr, input string) (bool, error) {
	// 解析正则表达式
	re, err := syntax.Parse(expr, syntax.Perl)
	if err != nil {
		return false, fmt.Errorf("error parsing expression: %w", err)
	}

	// 优化正则表达式
	re = optimizeRegexp(re)

	// 编译正则表达式
	prog, err := syntax.Compile(re)
	if err != nil {
		return false, fmt.Errorf("error compiling expression: %w", err)
	}

	// 自定义匹配逻辑
	return customMatch(prog, input), nil
}

func customMatch(prog *syntax.Prog, input string) bool {
	pc := 0
	sp := 0
	stack := []int{}

	for pc < len(prog.Inst) {
		inst := prog.Inst[pc]
		switch inst.Op {
		case syntax.InstFail:
			return false
		case syntax.InstAlt:
			stack = append(stack, pc+int(inst.Arg))
			pc = int(inst.Out)
		case syntax.InstAltMatch:
			if sp < len(input) && input[sp] == inst.Rune[0] {
				stack = append(stack, pc+int(inst.Arg))
				pc = int(inst.Out)
			} else {
				pc++
			}
		case syntax.InstRune:
			if sp < len(input) && input[sp] == inst.Rune[0] {
				sp++
				pc = int(inst.Out)
			} else {
				if len(stack) > 0 {
					pc = stack[len(stack)-1]
					stack = stack[:len(stack)-1]
				} else {
					return false
				}
			}
		case syntax.InstMatch:
			return true
		default:
			pc++
		}
	}
	return false
}

在上述代码中,我们实现了一个简单的正则表达式引擎,通过解析、优化、编译和自定义匹配逻辑,实现了正则表达式的匹配功能。

结论

通过本文的介绍,我们深入了解了Go语言标准库中的regexp/syntax包。我们详细讲解了该包的结构和使用方法,包括解析、分析、优化、编译和自定义匹配逻辑。通过实战案例,我们展示了如何利用regexp/syntax包实现自定义的正则表达式引擎。

regexp/syntax包为开发者提供了强大的正则表达式底层操作能力,使我们能够深入理解和控制正则表达式的行为。希望本文能帮助读者更好地掌握regexp/syntax包的使用,提升正则表达式处理的效率和灵活性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2212706.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux下Git操作

一、基本命令 1、创建 git 目录&#xff08;工作区&#xff09; mkdir gitcode 2、创建本地仓库&#xff0c;生成 .git 隐藏目录 git init 3、设置配置项 git config user.name "xxx" git config user.email "....." 4、查看配置项 git config -l …

将SpringBoot的Maven项目打成jar包和war包

先需要明确的是&#xff0c;该项目打包的形态是可执行的jar包&#xff0c;还是在tomcat下运行的war包。 springboot自带的maven打包 1.创建一个springboot web项目 1.api控制层HelloWorld.java RestController RequestMapping("/hello") public class HelloWorld …

SpringBoot基础(五):集成JUnit5

SpringBoot基础系列文章 SpringBoot基础(一)&#xff1a;快速入门 SpringBoot基础(二)&#xff1a;配置文件详解 SpringBoot基础(三)&#xff1a;Logback日志 SpringBoot基础(四)&#xff1a;bean的多种加载方式 SpringBoot基础(五)&#xff1a;集成JUnit5 目录 一、JUnit…

使用dotnet-counters和dotnet-dump 分析.NET Core 项目内存占用问题

在.NET Core 项目部署后&#xff0c;我们往往会遇到内存占用越来越高的问题&#xff0c;但是由于项目部署在Linux上&#xff0c;因此无法使用VS的远程调试工具来排查内存占用问题。那么这篇文章我们大家一起来学习一下如何排查内存占用问题。 首先&#xff0c;我们来看一下应用…

Python | Leetcode Python题解之第478题在圆内随机生成点

题目&#xff1a; 题解&#xff1a; class Solution:def __init__(self, radius: float, x_center: float, y_center: float):self.xc x_centerself.yc y_centerself.r radiusdef randPoint(self) -> List[float]:u, theta random.random(), random.random() * 2 * mat…

rancher hello-world

创建一个Deployment, 只填名称和容器镜像rancher/hello-world 成功后: 查看日志 结果&#xff1a; 部署了工作负载。这个过程可能需要几分钟完成。 当您的工作负载部署完成后&#xff0c;它的状态将变为Active&#xff0c;您可以从项目的工作负载页面查看工作负载当前的状态…

Golang | Leetcode Golang题解之第475题供暖器

题目&#xff1a; 题解&#xff1a; func findRadius(houses, heaters []int) (ans int) {sort.Ints(houses)sort.Ints(heaters)j : 0for _, house : range houses {dis : abs(house - heaters[j])for j1 < len(heaters) && abs(house-heaters[j]) > abs(house-…

threejs 前言

Three.js 中文官方网站 一、项目结构 二、相关开源库 下面表格列举了一些Three.js相关的开源库。

【赵渝强老师】K8s中Deployment控制器与StatefulSet控制器的区别

一、K8s的Deployment与StatefulSets 在K8s中&#xff0c;Deployment将Pod部署成无状态的应用程序&#xff0c;它只关心Pod的数量、Pod更新方式、使用的镜像和资源限制等。由于是无状态的管理方式&#xff0c;因此Deployment中没有角色和顺序的概念&#xff0c;换句话说&#xf…

关于VS Studio2022如何使用scanf函数

前言&#xff1a; 小编在最近给别人安装VS2022的时候&#xff0c;忘记让他弄一段代码来解决VS不能使用scanf函数这个问题了&#xff0c;导致他编写代码的时候出错了&#xff0c;小编考虑到可能有一些读者朋友同样也会遇到这种问题&#xff0c;于是我就写下了这一篇文章来帮助一…

并发编程-线程池

并发编程-线程池 本篇我们主要围绕线程池的原理以及源码进行分析&#xff0c;事实上线程池本身并不是什么新的技术&#xff0c;而是在池化技术的思想上把一些工具类整合起来。话不多说&#xff0c;我们开始进入正题。我们先来认识一下什么是线程池 概念 线程池&#xff08;T…

Linux进程间通信(一)——管道通信

目录 前言 1.管道实现进程间通信 ①管道的所属问题 ②匿名管道通信 ③命名管道通信 2.使用管道通信实现一个进程池 ①进程池类图 ②Channel类实现 ③ProcessPoll类实现 ④代码一览 前言 在学习Linux中的进程时&#xff0c;曾提到过进程的独立性。进程独立性的是进程与进程之间…

SpringMVC后台控制端校验-表单验证深度分析与实战优化

前言 在实战开发中&#xff0c;数据校验也是十分重要的环节之一&#xff0c;数据校验大体分为三部分&#xff1a; 前端校验后端校验数据库校验 本文讲解如何在后端控制端进行表单校验的工作 案例实现 在进行项目开发的时候,前端(jquery-validate),后端,数据库都要进行相关的数据…

【数据结构】图的最短路径

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C游记》《进击的C》《Linux迷航》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、最短路径的概念二、Dijkstra算法2.1 思想2.2 实现 三、Bellman-Ford算法3.1 思想3.2 实现 四、Floyd-Warsh…

操作教程|基于DataEase用RFM分析法分析零售交易数据

DataEase开源BI工具可以在店铺运营的数据分析及可视化方面提供非常大的帮助。同样&#xff0c;在用于客户评估的RFM&#xff08;即Recency、Frequency和Monetary的简称&#xff09;分析中&#xff0c;DataEase也可以发挥出积极的价值&#xff0c;通过数据可视化大屏的方式实时展…

液态神经网络 LNN

神经网络 (NN) 是 机器学习 模仿人脑结构和运算能力以从训练数据中识别模式的算法。 通过处理和传输信息的互连人工神经元网络&#xff0c;神经网络可以执行复杂的任务&#xff0c;例如 人脸识别, 自然语言理解&#xff0c;以及无需人工协助的预测分析。 尽管神经网络是一种强…

Mac电脑SourceTree git账号密码更改提示再次输入密码

前言&#xff1a; 最近小编git账号密码修改了&#xff0c;之前在sourceTree的git仓库在拉代码提交代码就会报错&#xff0c;提示因为密码导致的仓库连接失败。 解决方案 1.在mac电脑应用程序中搜索“钥匙串” 点击钥匙串访问 在钥匙串中选登录&#xff0c;在在右侧列表中找…

key形式和key/value形式二叉树

首先模拟一下key形式类 使用的结构是搜索二叉树 结点中有左孩子和右孩子 还有一个存储的值 template <class K>struct BSTnode//搜索二叉树不支持修改 中序遍历是有序的{K _key;BSTnode<K>* _left;BSTnode<K>* _right;BSTnode(const K& key):_key(key…

【C++】12.string类的使用

文章目录 1. 为什么学习string类&#xff1f;1.1 C语言中的字符串1.2 两个面试题(暂不做讲解) 2. 标准库中的string类2.1 string类(了解)2.2 auto和范围for 3. 查看技术文档4. string的访问5. 如何读取每个字符呢&#xff1f;6. auto语法糖&#xff08;C11&#xff09;7. 范围f…

spring boot 2.7整合Elasticsearch Java client + ingest attachment实现文档解析

一、软件环境 软件版本号备注Spring boot2.7.23.x版本建议使用ElasticSearch8.xElasticSearch7.17.4ElasticSearch 7.x 可使用JDK 8 ElasticSearch 8.x 要求使用JDK 11 二、安装ElasticSearch 下载地址&#xff1a;https://artifacts.elastic.co/downloads/elasticsearch/el…