golang实现前缀数实现匹配路由和获取路由参数

文章目录


前言

golang实现前缀数实现匹配路由和获取路由参数:


一、前缀树是什么?

前缀树:

又称单词查找树,字典树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。

二、需求定义

使用前缀树 匹配路由

提取路由上的参数规则: 定义路由/v1/{a},其中a就是参数名,请求路由/v1/123,那么a=123

可以定义多个参数, 如: 定义路由/v1/{a}/{b}/{c},其中就有 a,b,c 3个路由参数

必须匹配完,如: 定义路由/v1/{a}/{b}则/v1/123/456能匹配上,/v1/123不能匹配上

不允许的规则,如: /v1/* /v1/{a} 两个都不能用,相互冲突

代码如下(示例):

go 复制代码
package main

import (
	"log"
	"strings"
)

// 前缀树结构
type Trie struct {
	next map[string]*Trie
	isWord bool
}

func NewTrie() Trie {
	root := new(Trie)
	root.next = make(map[string]*Trie)
	root.isWord = false
	return *root
}

// 插入数据, 路由根据 "/" 进行拆分
func (t *Trie) Insert(word string) {
	for _, v := range strings.Split(word, "/") {
		if t.next[v] == nil {
			node := new(Trie)
			node.next = make(map[string]*Trie)
			node.isWord = false
			t.next[v] = node
		}
		// * 匹配所有
		// {X}  匹配路由参数 X
		if v == "*" || strings.Index(v, "{") != -1 {
			t.isWord = true
		}
		t = t.next[v]
	}
	t.isWord = true
}

// 匹配路由
func (t *Trie) Search(word string) (isHave bool, arg map[string]string) {
	arg = make(map[string]string)
	isHave = false
	for _, v := range strings.Split(word, "/") {
		if t.isWord {
			for k,_ := range t.next {
				if strings.Index(k, "{") != -1 {
					key := strings.Replace(k, "{", "", -1)
					key = strings.Replace(key, "}", "", -1)
					arg[key] = v
				}
				v = k
			}
			//log.Println("v = ", v)
		}
		if t.next[v] == nil {
			log.Println("找不到了, 匹配不上")
			return
		}
		t = t.next[v]
	}
	//log.Println(t.next, len(t.next))
	// 必须匹配全  比如: /v1/{b}/{a}  /v1/123匹配不到, /v1/123/456才可匹配
	if len(t.next) == 0 {
		isHave = t.isWord
		return
	}
	return
}

// 打印树
func (t *Trie) Show(){
Loop:
	if t == nil {
		log.Println("end")
		return
	}
	log.Println(t)
	for _, v :=range t.next {
		t = v
		goto Loop
	}

}

func main(){

	// 1. 使用前缀树 匹配路由
	// 2. 提取路由上的参数规则:  定义路由/v1/{a},其中a就是参数名,请求路由/v1/123,那么a=123
	// 3. 可以定义多个参数, 如: 定义路由/v1/{a}/{b}/{c},其中就有 a,b,c 3个路由参数
	// 4. 必须匹配完,如: 定义路由/v1/{a}/{b}则/v1/123/456能匹配上,/v1/123不能匹配上
	// 5. 不允许的规则,如:  /v1/*  /v1/{a}  两个都不能用,相互冲突

	t := NewTrie()
	t.Insert("/")
	t.Insert("H/e/c/{b}/{a}")
	t.Insert("a/e/c/l/o")
	t.Insert("e/c/c/*")// 任意的 无法取 *的值
	t.Insert("e/c/c/{a}/{a}") // 只取后一个a
	t.Insert("/v1/*")
	t.Insert("/v1/{a}")
	t.Show()
	//isok, cs := t.Search("H/e/c/asdasd/asdasd")
	//isok, cs := t.Search("/v1/123")
	isok, cs := t.Search("/")
	log.Println(isok, cs)

	//fmt.Print(t.Search("H/e/l/l/aaa"),"\n")

}
相关推荐
lsswear15 分钟前
Python 并发 线程
开发语言·python
郑州光合科技余经理24 分钟前
国际版外卖系统:税率字段怎么和订单主流程解耦
android·java·开发语言·前端·后端·php·ai编程
软件课代表CiCi39 分钟前
运行库是什么?电脑缺运行库怎么办?c++运行库缺失修复全攻略
开发语言·c++·windows·电脑·dll修复·dll丢失·运行库
Ivanqhz1 小时前
MLIR OpBuilder
开发语言·python·mlir
红宝村村长2 小时前
windows笔记本双系统ubuntu设置
开发语言
菜鸟~noob2334 小时前
【电子战】第15篇:混合定位——TDOA/FDOA/AOA 联合【含matlab代码】
开发语言·matlab
我不会起名字3224 小时前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣
Dreams_l5 小时前
死信队列和延迟队列介绍
java·开发语言
Zenova EdgeOS5 小时前
Python 工业边缘 redis-py 异步实战
开发语言·redis·python
君顾16 小时前
西安 24 小时自助健身房系统开发实战指南
java·开发语言·健身房