Package: trieregex
trieregextrieregexcreates efficientregular expressions(regexes) by storing a list of words in atriestructure, and translating the trie into a more compact pattern.The speed performance of a trie-based regex (e.g.r'(?:under(?:sta(?:nd|te))|take|go)?)'), compared to a flat regex union (i.e.,r'(?:understand|understate|undertake|undergo)', becomes obvious when using extremely large word lists, and especially when more specific or complicated contexts are specified at the boundaries. The processing time of using this package itself is also minimized withmemoization.InstallationpipinstalltrieregexUsageimportrefromtrieregeximportTrieRegExasTREwords=['lemon','lime','pomelo','orange','citron']more_words=['grapefruit','grape','tangerine','tangelo']# Initialize class instancetre=TRE()# Add word(s)tre=TRE(*words)# word(s) can be added upon instance creation, or aftertre.add('kumquat')# add one wordtre.add(*more_words)# add a list of words# Remove word(s)tre.remove('citron')# remove one wordtre.remove(*words)# remove a list of words# Check if a word exists in the trietre.has('citron')# Returns: Falsetre.has('tangerine')# Returns: True# Create regex pattern from the trietre.regex()# Returns: '(?:tange(?:rine|lo)|grape(?:fruit)?|kumquat)'# Add boundary context and compile for matchingpattern=re.compile(f'\\b{tre.regex()}\\b')# OR rf'\b{tre.regex()}\b'pattern# Returns: re.compile('\\b(?:tange(?:rine|lo)|grape(?:fruit)?|kumquat)\\b')pattern.findall("A kumquat is tastier than a loquat")# Returns: ['kumquat']# Inspect unique initial characters in the trietre.initials()# Returns: ['g', 'k', 't']# Inspect unique final characters in the trietre.finals()# Returns: ['e', 'o', 't']The last two methods are intended for the user to check what boundary contexts may be appropriate to set in the final regex. More discussed below.Boundariestrieregexdoes not include any default boundaries (such asr'\b') in the pattern returned from itsTrieRegEx.regex()method, so that the user can determine what is appropriate for their particular use case.Consider a fictitious brand name!Citruswith an exclamation mark at the beginning, usingr'\b'to define its boundaries in an attempt to catch it:string='I love !Citrus products!'re.findall(r'\b(!Citrus)\b',string)# Returns: []There.findall()call returns an empty list because the firstr'\b'is not matched. Whiler'\b'stands for the boundary between a word character and a non-word character, the exclamation mark and its preceding space character are both non-word characters.An appropriate regex for catching'!Citrus'can be written as follows, where the context before the exclamation mark is either start-of-string (r'^') or a non-word character (r'[^\w]'):re.findall(r'(?:^|[^\w])(!Citrus)\b',string)# Returns: ['!Citrus']This package was designed to allow any pattern in its trie, not just normal words bound by space and punctuation, so that the user can define their own regex context, and have the option to avoid data normalization when it is undesirable.Python version comptabilityDue tof-stringsand type hints, this package is only comptible with Python versions >=3.6.For Python versions >=2.7, <3.6, backports such asfuture-fstringsandtypingare available.