boyer_moore 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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!