Module: XRay::SearchPattern

Defined in:
lib/aws-xray-sdk/search_pattern.rb

Overview

custom pattern matching for performance and the SDK use cases.

Class Method Summary collapse

Class Method Details

.simple_wildcard_match?(pattern:, text:) ⇒ Boolean

Returns:

  • (Boolean)


61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/aws-xray-sdk/search_pattern.rb', line 61

def self.simple_wildcard_match?(pattern:, text:)
  j = 0
  pattern_len = pattern.length
  text_len = text.length
  (0...pattern_len).each do |i|
    p = pattern[i]
    # Presumption for this method is that globs only occur at end
    return true if p == '*'
    if p == '?'
      # No character to match
      return false if j == text_len
    else
      return false if j >= text_len || p != text[j]
    end
    j += 1
  end
  # Ate up all the pattern and didn't end at a glob, so a match
  # will have consumed all the text
  j == text_len
end

.wildcard_match?(pattern:, text:, case_insensitive: true) ⇒ Boolean

Performs a case-insensitive wildcard match against two strings. This method works with pseduo-regex chars; specifically ? and * are supported. An asterisk (*) represents any combination of characters. A question mark (?) represents any single character.

Parameters:

  • pattern (String)

    The regex-like pattern to be compared against.

  • text (String)

    The string to compare against the pattern.

  • case_insensitive (defaults to: true)

    A boolean flag. Default is true.

Returns:

  • (Boolean)


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/aws-xray-sdk/search_pattern.rb', line 11

def self.wildcard_match?(pattern:, text:, case_insensitive: true)
  return false unless pattern && text
  pattern_len = pattern.length
  text_len = text.length
  return text_len.zero? if pattern_len.zero?
  # Check the special case of a single * pattern, as it's common
  return true if pattern == '*'

  if case_insensitive
    # do not mutate original input
    pattern = pattern.downcase
    text = text.downcase
  end
  # Infix globs are relatively rare, and the below search is expensive.
  # Check for infix globs and, in their absence, do the simple thing.
  if !pattern.include?('*') || pattern.index('*') == pattern_len - 1
    return simple_wildcard_match? pattern: pattern, text: text
  end

  # The res[i] is used to record if there is a match between
  # the first i chars in text and the first j chars in pattern.
  # So will return res[textLength+1] in the end
  # Loop from the beginning of the pattern
  # case not '*': if text[i]==pattern[j] or pattern[j] is '?',
  # and res[i] is true, set res[i+1] to true, otherwise false.
  # case '*': since '*' can match any globing, as long as there is a true
  # in res before i, all the res[i+1], res[i+2],...,res[textLength]
  # could be true
  res = Array.new(text_len + 1)
  res[0] = true
  (0...pattern_len).each do |j|
    p = pattern[j]
    if p != '*'
      (text_len - 1).downto(0) do |i|
        res[i + 1] = res[i] && (p == '?' || (p == text[i]))
      end
    else
      i = 0
      i += 1 while i <= text_len && !res[i]
      (i..text_len + 1).each do |m|
        res[m] = true
      end
    end
    res[0] = res[0] && (p == '*')
  end
  res[text_len]
end