本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

147 lines
2.8KB

  1. package match
  2. import (
  3. "fmt"
  4. "unicode/utf8"
  5. )
  6. type BTree struct {
  7. Value Matcher
  8. Left Matcher
  9. Right Matcher
  10. ValueLengthRunes int
  11. LeftLengthRunes int
  12. RightLengthRunes int
  13. LengthRunes int
  14. }
  15. func NewBTree(Value, Left, Right Matcher) (tree BTree) {
  16. tree.Value = Value
  17. tree.Left = Left
  18. tree.Right = Right
  19. lenOk := true
  20. if tree.ValueLengthRunes = Value.Len(); tree.ValueLengthRunes == -1 {
  21. lenOk = false
  22. }
  23. if Left != nil {
  24. if tree.LeftLengthRunes = Left.Len(); tree.LeftLengthRunes == -1 {
  25. lenOk = false
  26. }
  27. }
  28. if Right != nil {
  29. if tree.RightLengthRunes = Right.Len(); tree.RightLengthRunes == -1 {
  30. lenOk = false
  31. }
  32. }
  33. if lenOk {
  34. tree.LengthRunes = tree.LeftLengthRunes + tree.ValueLengthRunes + tree.RightLengthRunes
  35. } else {
  36. tree.LengthRunes = -1
  37. }
  38. return tree
  39. }
  40. func (self BTree) Len() int {
  41. return self.LengthRunes
  42. }
  43. // todo?
  44. func (self BTree) Index(s string) (int, []int) {
  45. return -1, nil
  46. }
  47. func (self BTree) Match(s string) bool {
  48. inputLen := len(s)
  49. // self.Length, self.RLen and self.LLen are values meaning the length of runes for each part
  50. // here we manipulating byte length for better optimizations
  51. // but these checks still works, cause minLen of 1-rune string is 1 byte.
  52. if self.LengthRunes != -1 && self.LengthRunes > inputLen {
  53. return false
  54. }
  55. // try to cut unnecessary parts
  56. // by knowledge of length of right and left part
  57. var offset, limit int
  58. if self.LeftLengthRunes >= 0 {
  59. offset = self.LeftLengthRunes
  60. }
  61. if self.RightLengthRunes >= 0 {
  62. limit = inputLen - self.RightLengthRunes
  63. } else {
  64. limit = inputLen
  65. }
  66. for offset < limit {
  67. // search for matching part in substring
  68. index, segments := self.Value.Index(s[offset:limit])
  69. if index == -1 {
  70. releaseSegments(segments)
  71. return false
  72. }
  73. l := s[:offset+index]
  74. var left bool
  75. if self.Left != nil {
  76. left = self.Left.Match(l)
  77. } else {
  78. left = l == ""
  79. }
  80. if left {
  81. for i := len(segments) - 1; i >= 0; i-- {
  82. length := segments[i]
  83. var right bool
  84. var r string
  85. // if there is no string for the right branch
  86. if inputLen <= offset+index+length {
  87. r = ""
  88. } else {
  89. r = s[offset+index+length:]
  90. }
  91. if self.Right != nil {
  92. right = self.Right.Match(r)
  93. } else {
  94. right = r == ""
  95. }
  96. if right {
  97. releaseSegments(segments)
  98. return true
  99. }
  100. }
  101. }
  102. _, step := utf8.DecodeRuneInString(s[offset+index:])
  103. offset += index + step
  104. releaseSegments(segments)
  105. }
  106. return false
  107. }
  108. func (self BTree) String() string {
  109. const n string = "<nil>"
  110. var l, r string
  111. if self.Left == nil {
  112. l = n
  113. } else {
  114. l = self.Left.String()
  115. }
  116. if self.Right == nil {
  117. r = n
  118. } else {
  119. r = self.Right.String()
  120. }
  121. return fmt.Sprintf("<btree:[%s<-%s->%s]>", l, self.Value, r)
  122. }
上海开阖软件有限公司 沪ICP备12045867号-1