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.

78 lines
2.6 KiB

  1. // Copyright (c) 2016 Couchbase, Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package camelcase
  15. import (
  16. "bytes"
  17. "unicode/utf8"
  18. "github.com/blevesearch/bleve/analysis"
  19. "github.com/blevesearch/bleve/registry"
  20. )
  21. const Name = "camelCase"
  22. // CamelCaseFilter splits a given token into a set of tokens where each resulting token
  23. // falls into one the following classes:
  24. // 1) Upper case followed by lower case letters.
  25. // Terminated by a number, an upper case letter, and a non alpha-numeric symbol.
  26. // 2) Upper case followed by upper case letters.
  27. // Terminated by a number, an upper case followed by a lower case letter, and a non alpha-numeric symbol.
  28. // 3) Lower case followed by lower case letters.
  29. // Terminated by a number, an upper case letter, and a non alpha-numeric symbol.
  30. // 4) Number followed by numbers.
  31. // Terminated by a letter, and a non alpha-numeric symbol.
  32. // 5) Non alpha-numeric symbol followed by non alpha-numeric symbols.
  33. // Terminated by a number, and a letter.
  34. //
  35. // It does a one-time sequential pass over an input token, from left to right.
  36. // The scan is greedy and generates the longest substring that fits into one of the classes.
  37. //
  38. // See the test file for examples of classes and their parsings.
  39. type CamelCaseFilter struct{}
  40. func NewCamelCaseFilter() *CamelCaseFilter {
  41. return &CamelCaseFilter{}
  42. }
  43. func (f *CamelCaseFilter) Filter(input analysis.TokenStream) analysis.TokenStream {
  44. rv := make(analysis.TokenStream, 0, len(input))
  45. nextPosition := 1
  46. for _, token := range input {
  47. runeCount := utf8.RuneCount(token.Term)
  48. runes := bytes.Runes(token.Term)
  49. p := NewParser(runeCount, nextPosition, token.Start)
  50. for i := 0; i < runeCount; i++ {
  51. if i+1 >= runeCount {
  52. p.Push(runes[i], nil)
  53. } else {
  54. p.Push(runes[i], &runes[i+1])
  55. }
  56. }
  57. rv = append(rv, p.FlushTokens()...)
  58. nextPosition = p.NextPosition()
  59. }
  60. return rv
  61. }
  62. func CamelCaseFilterConstructor(config map[string]interface{}, cache *registry.Cache) (analysis.TokenFilter, error) {
  63. return NewCamelCaseFilter(), nil
  64. }
  65. func init() {
  66. registry.RegisterTokenFilter(Name, CamelCaseFilterConstructor)
  67. }