Thompson构造法构造简单正则自动机转换表并模拟运行(未完善)

有BUG或意见欢迎留言

package main

import (
	"fmt"
)

type treeNode struct {
	value uint8
	lNode *treeNode
	rNode *treeNode
}

// 接口定义泛型可以接收的数据类型
type dataType interface {
	*treeNode | uint8 | int
}

// 使用泛型定义栈
type stack[T dataType] struct {
	data []T
	top  int
}

// 实现栈的push方法
func (i *stack[T]) push(data T) bool {
	if (*i).top < len((*i).data) { //如果没有超出容量则直接赋值
		(*i).data[(*i).top] = data
	} else {
		(*i).data = append((*i).data, data) //否则扩容
	}
	(*i).top++ //栈顶增长
	return true
}

// 获取栈顶元素,不删除
func (i *stack[T]) getTop() T {
	return (*i).data[(*i).top-1]
}

// 实现栈的pop方法,获取栈顶元素并删除
func (i *stack[T]) pop() T {
	(*i).top--
	return (*i).data[(*i).top]
}

// 清空栈
func (i *stack[T]) empty() {
	(*i).top = 0
}

// 获取所有数据
func (i *stack[T]) getData() []T {
	return (*i).data[0:(*i).top]
}

// 如果需要改变数据结构的内容则接收者为指针,否则接收者为类型
func (i *stack[T]) isEmpty() bool {
	return (*i).top == 0
}

// 从另一个栈初始化,复制全部内容
func (i *stack[T]) copyAnotherStack(tempStack stack[T]) {
	(*i).data = tempStack.data
	(*i).top = tempStack.top
}

var largestState int
var cStack stack[uint8]
var nodeStack stack[*treeNode]
var newStateStack stack[int]
var oldStateStack stack[int]
var alreadyOn []uint8

// map数组,存放转换表
var stateMap map[int]map[uint8][]int = make(map[int]map[uint8][]int)

// 返回指定数量的新状态
func getNewState(num int) []int {
	var numArray []int = make([]int, num)
	for i := 0; i < num; i++ {
		numArray[i] = largestState + i
	}
	largestState = largestState + num
	return numArray
}

// 打印一棵树,采用中序遍历,即中-左-右
func printTree(tempTree *treeNode) {
	fmt.Printf("%c\n", (*tempTree).value)
	if (*tempTree).lNode != nil {
		printTree((*tempTree).lNode)
	}
	if (*tempTree).rNode != nil {
		printTree((*tempTree).rNode)
	}
}

// 打印转换表
func printStateMap() {
	for key, item := range stateMap { //遍历每个初始状态
		fmt.Printf("初始状态state为%d,  ", key)
		for k, i := range item { //遍历每个状态的转换字符
			if k == 0 {
				k = '0'
			}
			fmt.Printf("转换字符为%c,转换后状态为%v\n", k, i)
		}
	}
}

// 插入单个状态在单个字符下的转换
func makeMapping(state int, c uint8, destState []int) {
	//如果map不存在,需要创建后才能使用
	if stateMap[state] == nil {
		//先初始化map才能使用
		stateMap[state] = make(map[uint8][]int)
		stateMap[state][c] = destState
	} else {
		//如果已存在,则将目标状态插在最后
		//可能出现状态重复
		stateMap[state][c] = append(stateMap[state][c], destState...)
	}
}

// 分析一棵树 slice是值传递 数组也是值传递  array *[3]int 指针传递,但使用指针无法append数组
// 返回值开始state 转换字母 接收state

func analyzeTree(tempTree *treeNode) ([]int, []int) {
	//处理单个字符
	if (*tempTree).lNode == nil && (*tempTree).rNode == nil {
		startState := getNewState(1)
		receiveState := getNewState(1)
		makeMapping(startState[0], (*tempTree).value, receiveState)
		return startState, receiveState
	}
	//处理连接符
	if (*tempTree).value == '.' {
		lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
		rStartState, rReceiveState := analyzeTree((*tempTree).rNode)
		//遍历前字符的接收状态集 将前字符的接收状态集和后字符串的开始状态集用空串映射连起来
		for _, item := range lReceiveState {
			makeMapping(item, 0, rStartState)
		}
		return lStartState, rReceiveState
	} else if (*tempTree).value == '*' {
		lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
		//新建开始集和接收集
		startState := getNewState(1)
		receiveState := getNewState(1)
		appendStates := append(lStartState, receiveState[0])
		//开始集用空串映射到左节点的开始集和结束集
		makeMapping(startState[0], 0, appendStates)
		//遍历左节点结束集
		for _, item := range lReceiveState {
			//左节点结束集用空串映射到左节点开始集和结束集
			makeMapping(item, 0, appendStates)
		}
		return startState, receiveState
	} else if (*tempTree).value == '+' {
		lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
		//新建开始集和接收集
		startState := getNewState(1)
		receiveState := getNewState(1)
		//开始集用空串映射到左节点的开始集
		makeMapping(startState[0], 0, lStartState)
		//遍历左节点结束集
		for _, item := range lReceiveState {
			//左节点结束集用空串映射到左节点开始集和结束集
			makeMapping(item, 0, append(lStartState, receiveState[0]))
		}
		return startState, receiveState
	} else if (*tempTree).value == '|' {
		//初始化左右节点各自的开始集和结束集
		lStartState, lReceiveState := analyzeTree((*tempTree).lNode)
		rStartState, rReceiveState := analyzeTree((*tempTree).rNode)
		//初始化开始集和结束集
		startState := getNewState(1)
		receiveState := getNewState(1)
		//开始集用空串映射到左右节点各自的开始集
		makeMapping(startState[0], 0, append(lStartState, rStartState...))
		//遍历左节点的结束集
		for _, item := range lReceiveState {
			//左节点结束集用空串映射到结束集
			makeMapping(item, 0, receiveState)
		}
		//遍历右节点的结束集
		for _, item := range rReceiveState {
			//右节点结束集用空串映射到结束集
			makeMapping(item, 0, receiveState)
		}
		return startState, receiveState
	}
	return nil, nil
}

// 在数组中查找
func findNumInArray(num int, array []int) int {
	for index, item := range array {
		if item == num {
			return index //成功返回索引
		}
	}
	return -1 //否则返回-1
}

// 空转换和普通转换不同,需要递归,故不能合在一起
func findZeroMapping(startState []int) {
	for _, item := range startState {
		//将状态插入
		if alreadyOn[item] == 0 {
			oldStateStack.push(item)
			alreadyOn[item] = 1
			//只有未被插入才需要继续处理目标状态
			//先排除该状态没有转换路线 再排除0转换的目标状态为空切片
			if stateMap[item] != nil && len(stateMap[item][0]) != 0 {
				//继续处理0转换目标状态
				findZeroMapping(stateMap[item][0])
			}
		}

	}
}

// 找出所有空转换的结果
func findMapping(state []int, c uint8) {
	//遍历输入的state数组
	for _, item := range state {
		//先排除该状态没有转换路线 再排除c转换的目标状态为空切片
		if stateMap[item] != nil && len(stateMap[item][c]) != 0 {
			//将目标状态加入newStateStack
			for _, i := range stateMap[item][c] {
				if alreadyOn[i] == 0 {
					newStateStack.push(i)
					alreadyOn[i] = 1
				}
			}
		}
	}
}

// 实现match函数

func matchString(str string, startState []int, receiveState []int) string {
	//创建alreadyOn数组
	alreadyOn = make([]uint8, largestState)
	//初始化oldStateStack
	findZeroMapping(startState)
	var matchPos int
	length := len(str)
	var state []int
	//采用i遍历,方便回退
	for i := 0; i < length; i++ {
		//重新创建alreadyOn数组
		alreadyOn = make([]uint8, largestState)
		//获取oldStateStack数据
		state = oldStateStack.getData()
		//以下为常用调试语句
		//fmt.Println(state)
		//清空oldStateStack
		oldStateStack.empty()
		//使用oldStateStack数据初始化newStateStack
		findMapping(state, str[i])
		//重新创建alreadyOn数组
		alreadyOn = make([]uint8, largestState)
		//如果转换的目标状态为空,则重置状态
		if newStateStack.isEmpty() {
			//重置前判断是否已匹配到
			for _, item := range state {
				if findNumInArray(item, receiveState) != -1 {
					return str[matchPos:i]
				}
			}
			//重置匹配开始字符
			i = matchPos
			//记录新的匹配开始字符
			matchPos++
			//初始化oldStateStack
			findZeroMapping(startState)
		} else {
			//获取新栈的值
			state = newStateStack.getData()
			//清空新栈
			newStateStack.empty()
			//使用新栈初始化旧栈
			findZeroMapping(state)
		}
	}
	//匹配完后检查最终状态
	state = oldStateStack.getData()
	for _, item := range state {
		if findNumInArray(item, receiveState) != -1 {
			return str[matchPos:] //如果含有接收态,则接收
		}
	}
	return ""
}
func main() {
	var str string = "a+b|c"
	for _, c := range str {
		if (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') { //当遇到字母,与前一部分连接
			//如果节点栈非空,且上一运算符是'|'
			if !nodeStack.isEmpty() && !cStack.isEmpty() && cStack.getTop() == '|' {
				//获取左节点
				lNode := nodeStack.pop()
				//新建或节点并初始化或节点的左右节点
				nodeStack.push(&treeNode{cStack.pop(), lNode, &treeNode{uint8(c), nil, nil}})
			} else {
				if !nodeStack.isEmpty() {
					//连接符采用'.'
					cStack.push('.')
				}
				nodeStack.push(&treeNode{uint8(c), nil, nil})
			}
		} else if c == '*' {
			//理论上'*'的优先级比'+'高 获取左节点
			lNode := nodeStack.pop()
			//压栈'*'
			nodeStack.push(&treeNode{'*', lNode, nil})
		} else if c == '|' {
			//'|直接压栈'
			cStack.push('|')
		} else if c == '+' {
			//获取左节点
			lNode := nodeStack.pop()
			//压栈'+' 由于'+'被连接符号占用,需改用
			nodeStack.push(&treeNode{'+', lNode, nil})
		}
	}
	//在操作符栈非空的时间内
	for !cStack.isEmpty() {
		c := cStack.pop()
		rNode := nodeStack.pop()
		lNode := nodeStack.pop()
		nodeStack.push(&treeNode{c, lNode, rNode})
	}
	tree := nodeStack.pop()
	//初始化工作  初始化起始栈
	startState, receiveState := analyzeTree(tree)
	fmt.Printf("全局初始状态为%v,接收状态为%v\n", startState, receiveState)
	printTree(tree)
	printStateMap()
	//初始化old栈
	fmt.Println(matchString("baaaabc", startState, receiveState))
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蔡海航

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值