github.com/qiuhoude/go-web@v0.0.0-20220223060959-ab545e78f20d/algorithm/datastructures/dp/regex_pattern_test.go (about)

     1  package dp
     2  
     3  import (
     4  	"github.com/bmizerany/assert"
     5  	"testing"
     6  )
     7  
     8  // 正则匹配
     9  type Pattern struct {
    10  	matched bool   // 是否匹配的全局值
    11  	pattern []rune // 正则串
    12  }
    13  
    14  func NewPattern(expr string) *Pattern {
    15  	return &Pattern{pattern: []rune(expr)}
    16  }
    17  
    18  func (p *Pattern) Match(text string) bool { // 文本串及长度
    19  	p.matched = false
    20  	p.rmatch(0, 0, []rune(text))
    21  	//p.rmatchDp([]rune(text))
    22  	return p.matched
    23  }
    24  
    25  /*
    26  只有 * 和 ? 两种通配符
    27  * 表示任意多(>=0)个字符
    28  ? 表示0个或1任意字符
    29  
    30  使用回溯的方式实现
    31  
    32  ti 表示待匹配字符的指针
    33  pj 表示正则表达式指针位置
    34  */
    35  
    36  func (p *Pattern) rmatch(ti, pj int, text []rune) {
    37  	if p.matched { // 已经匹配
    38  		return
    39  	}
    40  	if pj == len(p.pattern) { // 正则串到结束
    41  		if ti == len(text) {
    42  			// 文本串也结束 找到匹配
    43  			p.matched = true
    44  		}
    45  		return
    46  	}
    47  	// -----递归出口分割线-----
    48  	switch {
    49  	case p.pattern[pj] == '*': // 匹配多个字符
    50  		for k := 0; k < len(text)-ti; k++ {
    51  			p.rmatch(ti+k, pj+1, text)
    52  		}
    53  	case p.pattern[pj] == '?': //匹配0个或1个
    54  		p.rmatch(ti, pj+1, text)
    55  		p.rmatch(ti+1, pj+1, text)
    56  	case ti < len(text) && p.pattern[pj] == text[ti]: // 纯字符匹配才能继续,也属于剪枝操作
    57  		p.rmatch(ti+1, pj+1, text)
    58  	}
    59  }
    60  
    61  // 使用动态规划的方式怎么写?
    62  // 状态 dp [ti][pj]bool 表示ti,pi的位置是否匹配
    63  func (p *Pattern) rmatchDp(text []rune) {
    64  	tn := len(text)
    65  	pn := len(p.pattern)
    66  
    67  	dp := make([][]bool, tn)
    68  	for i := range dp {
    69  		dp[i] = make([]bool, pn)
    70  	}
    71  	// init first line
    72  	switch p.pattern[0] {
    73  	case '*':
    74  		for i := 0; i < pn; i++ {
    75  			dp[0][i] = true
    76  		}
    77  	case '?':
    78  		dp[0][0] = true
    79  	case text[0]:
    80  		dp[0][0] = true
    81  	}
    82  	for ti := 1; ti < tn; ti++ {
    83  		for pi := 0; pi < pn; pi++ {
    84  			switch p.pattern[pi] {
    85  			case '*':
    86  
    87  			case '?':
    88  			case text[ti]:
    89  			}
    90  		}
    91  	}
    92  
    93  	p.matched = dp[tn-1][pn-1]
    94  }
    95  
    96  func TestMatch(t *testing.T) {
    97  	pattern := NewPattern("?c*html?")
    98  	assert.Equal(t, pattern.Match("chtml"), true)
    99  	assert.Equal(t, pattern.Match("cxxxxhtml"), true)
   100  	assert.Equal(t, pattern.Match("xxxxhtm"), false)
   101  
   102  }