boyer_moore 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 303f4624a20a48f5b2f8ea4784426ae186143943
4
- data.tar.gz: 7c7bc24d1d32a05c138fbf614928ca63e27db592
3
+ metadata.gz: 7de6b2a49229c15b9f3ab4a7311bcbd77789d02b
4
+ data.tar.gz: 21c26b9a7476405f08eaef5fc76f614496664850
5
5
  SHA512:
6
- metadata.gz: bb1abf64fd6b1cd88a721cc0cef3b7f19a80001865e112f2c599b290a22e79075a8516e8479aecded4a4b3ae27cfcfd6d94515748d1a96299f806ff2c0e596ce
7
- data.tar.gz: 16540ebe1554a24bfe620ae3dba30137ff96539e8887844f7545a30c2ef33d4ea08ca84b4f6abfc4a67ee4e249547c1beb708a030bc92b7dc038d7d71d6ebfff
6
+ metadata.gz: 6199a53c8228caded86afe336064ee3f0ae98008fba3786861f38b021f184c369efcd0bb9528fe86b26c1f03790599806483be4c89129258d845ec269193da86
7
+ data.tar.gz: acadd4c9f7de76fdc4e25e3208403eba5704949d177eccb41ee7f02eda772421851f13b010192b44388b2486d6728b2036f982d3dfa608ea44f11d9f154978e4
data/boyer_moore.gemspec CHANGED
@@ -26,6 +26,6 @@ Gem::Specification.new do |spec|
26
26
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
27
  spec.require_paths = ["lib"]
28
28
 
29
- spec.add_development_dependency "bundler", "~> 1.10"
30
- spec.add_development_dependency "rake", "~> 10.0"
29
+ spec.add_development_dependency "bundler"
30
+ spec.add_development_dependency "rake"
31
31
  end
data/lib/boyer_moore.rb CHANGED
@@ -1,108 +1,100 @@
1
- require "boyer_moore/version"
1
+ require_relative "./boyer_moore/version"
2
2
 
3
- class RichHash
4
-
5
- def initialize
6
- @regexps = {}
7
- @regular = {}
8
- end
3
+ module BoyerMoore
4
+ def self.search(haystack, needle_string)
5
+ needle = Needle.new(needle_string)
9
6
 
10
- def [](k)
11
- regular = @regular[k]
12
- return regular if regular
13
- if @regexps.size > 0
14
- @regexps.each do |regex,v|
15
- return v if regex.match(k)
7
+ haystack_index = 0
8
+ while haystack_index <= haystack.size - needle.size
9
+ if skip_by = needle.match_or_skip_by(haystack, haystack_index)
10
+ haystack_index += skip_by
11
+ else
12
+ break haystack_index # Found a match at haystack_index!
16
13
  end
17
14
  end
18
- nil
19
15
  end
20
16
 
21
- def []=(k,v)
22
- if k.kind_of?(Regexp)
23
- @regexps[k] = v
24
- else
25
- @regular[k] = v
17
+ class Needle
18
+ def initialize(needle)
19
+ needle.size > 0 or raise "Must pass needle with size > 0"
20
+ @needle = needle
26
21
  end
27
- end
28
-
29
- end
30
22
 
31
- module BoyerMoore
23
+ def size
24
+ @needle.size
25
+ end
32
26
 
33
- def self.search(haystack, needle)
34
- needle_len = needle.size
35
- haystack_len = haystack.size
36
- return nil if haystack_len == 0
37
- return haystack if needle_len == 0
38
- badcharacter = self.prepare_badcharacter_heuristic(needle)
39
- goodsuffix = self.prepare_goodsuffix_heuristic(needle)
40
- s = 0
41
- while s <= haystack_len - needle_len
42
- j = needle_len
43
- while (j > 0) && self.needle_matches?(needle[j-1], haystack[s+j-1])
44
- j -= 1
27
+ def match_or_skip_by(haystack, haystack_index)
28
+ if mismatch_idx = mismatch_index(haystack, haystack_index)
29
+ mismatch_char_index = character_index(haystack[haystack_index + mismatch_idx])
30
+ skip_by(mismatch_char_index, mismatch_idx)
45
31
  end
46
- if(j > 0)
47
- k = badcharacter[haystack[s+j-1]]
48
- k = -1 unless k
49
- if (k < j) && (m = j-k-1) > goodsuffix[j]
50
- s += m
51
- else
52
- s += goodsuffix[j]
53
- end
54
- else
55
- return s
32
+ end
33
+
34
+ private
35
+
36
+ def mismatch_index(haystack, haystack_index)
37
+ compare_index = size - 1
38
+ while @needle[compare_index] == haystack[haystack_index + compare_index]
39
+ compare_index -= 1
40
+ compare_index < 0 and return nil
56
41
  end
42
+ compare_index
57
43
  end
58
- return nil
59
- end
60
44
 
61
- def self.prepare_badcharacter_heuristic(str)
62
- result = RichHash.new
63
- 0.upto(str.length - 1) do |i|
64
- result[str[i]] = i
45
+ def character_index(char)
46
+ character_indexes[char] || -1
65
47
  end
66
- result
67
- end
68
48
 
69
- def self.prepare_goodsuffix_heuristic(normal)
70
- size = normal.size
71
- result = []
72
- reversed = normal.dup.reverse
73
- prefix_normal = compute_prefix(normal)
74
- prefix_reversed = compute_prefix(reversed)
75
- 0.upto(size) do |i|
76
- result[i] = size - prefix_normal[size-1]
49
+ def good_suffix(compare_index)
50
+ good_suffixes[compare_index]
77
51
  end
78
- 0.upto(size-1) do |i|
79
- j = size - prefix_reversed[i]
80
- k = i - prefix_reversed[i]+1
81
- result[j] = k if result[j] > k
52
+
53
+ def skip_by(mismatch_char_index, compare_index)
54
+ suffix_index = good_suffix(compare_index + 1)
55
+ if mismatch_char_index <= compare_index && (m = compare_index - mismatch_char_index) > suffix_index
56
+ m
57
+ else
58
+ suffix_index
59
+ end
82
60
  end
83
- result
84
- end
85
61
 
86
- def self.needle_matches?(needle, haystack)
87
- if needle.kind_of?(Regexp)
88
- needle.match(haystack) ? true : false
89
- else
90
- needle == haystack
62
+ def character_indexes
63
+ @char_indexes ||=
64
+ (0...@needle.length).reduce({}) do |hash, i|
65
+ hash[@needle[i]] = i
66
+ hash
67
+ end
68
+ end
69
+
70
+ def good_suffixes
71
+ @good_suffixes ||=
72
+ begin
73
+ prefix_normal = self.class.prefix(@needle)
74
+ prefix_reversed = self.class.prefix(@needle.reverse)
75
+ result = []
76
+ (0..@needle.size).each do |i|
77
+ result[i] = @needle.size - prefix_normal[@needle.size-1]
78
+ end
79
+ (0...@needle.size).each do |i|
80
+ j = @needle.size - prefix_reversed[i]
81
+ k = i - prefix_reversed[i] + 1
82
+ result[j] > k and result[j] = k
83
+ end
84
+ result
85
+ end
91
86
  end
92
- end
93
87
 
94
- def self.compute_prefix(str)
95
- size = str.length
96
- k = 0
97
- result = [0]
98
- 1.upto(size - 1) do |q|
99
- while (k > 0) && (str[k] != str[q])
100
- k = result[k-1]
88
+ def self.prefix(string)
89
+ k = 0
90
+ (1...string.length).reduce([0]) do |prefix, q|
91
+ while k > 0 && string[k] != string[q]
92
+ k = prefix[k - 1]
93
+ end
94
+ string[k] == string[q] and k += 1
95
+ prefix[q] = k
96
+ prefix
101
97
  end
102
- k += 1 if(str[k] == str[q])
103
- result[q] = k
104
98
  end
105
- result
106
99
  end
107
-
108
100
  end
@@ -1,3 +1,3 @@
1
1
  module BoyerMoore
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
data/test_file ADDED
@@ -0,0 +1 @@
1
+ 123456
metadata CHANGED
@@ -1,43 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: boyer_moore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sri Harsha Kappala
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-11-18 00:00:00.000000000 Z
11
+ date: 2016-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.10'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.10'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '10.0'
33
+ version: '0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '10.0'
40
+ version: '0'
41
41
  description: Ruby wrapper for Boyer-Moore - The fastest search strategy, ever!
42
42
  email:
43
43
  - sriharsha.kappala@hotmail.com
@@ -55,6 +55,7 @@ files:
55
55
  - boyer_moore.gemspec
56
56
  - lib/boyer_moore.rb
57
57
  - lib/boyer_moore/version.rb
58
+ - test_file
58
59
  homepage: https://github.com/sriharshakappala/boyer_moore
59
60
  licenses:
60
61
  - MIT
@@ -76,7 +77,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
77
  version: '0'
77
78
  requirements: []
78
79
  rubyforge_project:
79
- rubygems_version: 2.4.8
80
+ rubygems_version: 2.6.4
80
81
  signing_key:
81
82
  specification_version: 4
82
83
  summary: Ruby wrapper for BoyerMoore algorithm - The fastest search strategy, ever!