Advertisement
NyteOwlDave

Brute Force Pattern Matching

Feb 18th, 2019
179
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.80 KB | None | 0 0
  1.  
  2. """
  3.  
  4. FOR: Vishavjeet Thakur
  5. RE:
  6. https://www.facebook.com/groups/860936880721980/permalink/1269063029909361/
  7.  
  8. Tested with Python 3.6.1
  9.  
  10. Searches for a pattern within a string.
  11.  
  12. Example 1
  13. ---------
  14. Input
  15.  String "pypropy"
  16. Pattern
  17.  String "aba"
  18. Output
  19.  1 (success)
  20.  
  21. Example 2
  22. ---------
  23. Input
  24.  String "aba"
  25. Pattern
  26.  String "xyz"
  27. Output
  28.  0 (failure)
  29.  
  30. The algorithm involves assigning alias symbols for
  31. each unique character within a given substring.
  32. The order of the alias symbols must match the order
  33. established in the pattern string.
  34.  
  35. """
  36.  
  37. # Set this to false for silent running
  38. verbose_mode = True
  39.  
  40. # Used to implement verbose/silent mode
  41. def message(msg):
  42.   if (verbose_mode):
  43.     print(msg)
  44.  
  45. """
  46. Represents a pattern (list of alias symbols)
  47. Maps each alias symbol to a position (0-based)
  48. """
  49. class Pattern:
  50.   # Pass in a pattern string
  51.   def __init__(self,pat):
  52.     self.chars = [alias for alias in pat]
  53.     self.dump()
  54.   # Return count of alias letters
  55.   def count(self):
  56.     return len(self.chars)
  57.     # Determine if alias exists in pattern
  58.   def contains(self, alias):
  59.     return alias in self.chars
  60.   # Return alias char at given index
  61.   def alias_at(self,index):
  62.     return self.chars[index]
  63.   # Determine if alias char matches alias at index
  64.   def match_at(self,index,alias):
  65.     return alias == self.chars[index]
  66.   # Dump state to console
  67.   def dump(self):
  68.     message("Pattern to match: {}".format(self.chars))
  69.  
  70. """
  71. Represents a dictionary
  72. Maps unique source characters to alias symbols
  73. """
  74. class Mapper:
  75.   # Constructor
  76.   def __init__(self):
  77.     self.chars = {}
  78.   # Remove all characters from dictionary
  79.   def clear(self):
  80.     self.chars = {}
  81.   # Return count of characters in dictionary
  82.   def count(self):
  83.     return len(self.chars)
  84.   # Determine if character exists in dictionary
  85.   def has_alias(self,char):
  86.     return char in self.chars
  87.   # Determine if an alias can be added
  88.   def can_add_alias(self,alias):
  89.     return alias not in self.chars.values()
  90.   # Add character and its alias to dictionary
  91.   def add_alias(self,char,alias):
  92.     message("Adding: '{}' alias '{}'".format(char,alias))
  93.     self.chars[char]=alias
  94.   # Return alias for a character
  95.   def get_alias(self,char):
  96.     return self.chars[char]
  97.   # Determine if character's alias matches
  98.   def matches(self,char,alias):
  99.     return self.chars[char] == alias
  100.   # Return string representation
  101.   def __str__(self):
  102.     return str(self.chars)
  103.   # Dump all aliases to console
  104.   def dump(self):
  105.     message("Mapper State:")
  106.     for char, alias in self.chars.items():
  107.       message("'{}' alias '{}'".format(char, alias))
  108.  
  109. """
  110. Prepresents an object that can
  111. compare a substring to a pattern.
  112. Substring size must be same as pattern size
  113. """
  114. class Comparer:
  115.   # Constructor (accepts pattern as a string)
  116.   def __init__(self,pat):
  117.     # Create a pattern object from string
  118.     self.pattern = Pattern(pat)
  119.     # Create a dictionary object for aliasing
  120.     self.mapper = Mapper()
  121.   # Determine if substring matches pattern
  122.   def matches(self,source):
  123.     # Check for length mismatch up front
  124.     if len(source) != self.pattern.count():
  125.       message("Error: source string too short")
  126.       return False # Failure
  127.     # Index into pattern list
  128.     index = 0
  129.     # Clear the alias dictionary
  130.     self.mapper.clear()
  131.     # Show substring to be compared
  132.     message("\n----------------")
  133.     message("Checking substring '{}'".format(source))
  134.     # For each source character
  135.     for ch in source:
  136.       message("Comparing '{}'".format(ch))
  137.       # If the char already has an alias
  138.       if self.mapper.has_alias(ch):
  139.         # Obtain the alias
  140.         alias = self.mapper.get_alias(ch)
  141.         message("Existing alias '{}'".format(alias))
  142.         # Look up the wanted alias at this index
  143.         wanted = self.pattern.alias_at(index)
  144.         message("Wanted alias '{}'".format(wanted))
  145.         # If the alias matches the pattern so far
  146.         if alias == wanted:
  147.           # Move to index of next alias in pattern
  148.           index += 1
  149.           # Go back for next character
  150.           continue
  151.         # The alias doesn't match
  152.         else:
  153.           message("Error: Alias mismatch!")
  154.           # Return failure code
  155.           return False
  156.       # This character has no alias yet
  157.       else:
  158.         # Grab a new alias from the pattern
  159.         alias = self.pattern.alias_at(index)
  160.         message("Assigning new alias: '{}'".format(alias))
  161.         # Make sure that this alias is unique
  162.         if not self.mapper.can_add_alias(alias):
  163.           message("Error: Duplicate!")
  164.           return False # Failure
  165.         # Map this alias to the character
  166.         self.mapper.add_alias(ch,alias)
  167.         # Move to index of next alias in pattern
  168.         index += 1
  169.         continue
  170.     # Success!
  171.     return True
  172.   # Dump internal state to console
  173.   def dump(self):
  174.     message("\nComparer State:")
  175.     self.pattern.dump()
  176.     self.mapper.dump()
  177.  
  178.  
  179. """
  180. Pattern matching function
  181. """
  182. def matchPattern(source,pat):
  183.   # Construct a comparer for substrings
  184.   comp = Comparer(pat)
  185.   # Get the pattern length
  186.   size = len(pat)
  187.   # Special case for zero size pattern
  188.   if size < 1:
  189.     return 0 # Failure
  190.   # So long as we has enough characters remaining
  191.   # for a possible match...
  192.   while len(source) >= size:
  193.     # Grab the next substring
  194.     chunk = source[0:size]
  195.     # Check for a match
  196.     if comp.matches(chunk):
  197.       message("\nMatched: {}".format(chunk))
  198.       return 1 # Success!
  199.     # Remove the first character from
  200.     # the source string
  201.     source = source[1:]
  202.   # Failed
  203.   comp.dump()
  204.   return 0
  205.  
  206. # Run test case
  207. if __name__ == "__main__":
  208.   source = "pypropy"
  209.   pattern = "aba"
  210.   result = matchPattern(source, pattern)
  211.   print("\nResult: {}".format(result))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement