Skip to main content

Efficient Trie-based regex unions for blacklist/whitelist filtering and one-pass mapping-based string replacing

Project description

retrie

build codecov pypi Version python downloads black

retrie offers fast methods to match and replace (sequences of) strings based on efficient Trie-based regex unions.

Trie

Instead of matching against a simple regex union, which becomes slow for large sets of words, a more efficient regex pattern can be compiled using a Trie structure:

from retrie.trie import Trie


trie = Trie()

assert trie.pattern() == ""

for term in ["abc", "foo", "abs"]:
    trie.add(term)
assert trie.pattern() == "(?:ab[cs]|foo)"  # equivalent to but faster than "(?:abc|abs|foo)"

trie.add("absolute")
assert trie.pattern() == "(?:ab(?:c|s(?:olute))|foo)"

trie.add("abx")
assert trie.pattern() == "(?:ab(?:[cx]|s(?:olute))|foo)"

trie.add("abxy")
assert trie.pattern() == "(?:ab(?:c|s(?:olute)|xy?)|foo)"

Installation

This pure-Python, OS independent package is available on PyPI:

$ pip install retrie

Usage

The following objects are all subclasses of retrie.retrie.Retrie, which handles filling the Trie and compiling the corresponding regex pattern.

Blacklist

The Blacklist object can be used to filter out bad occurences in a test or a sequenxce of strings:

from retrie.retrie import Blacklist

blacklist = Blacklist(["abc", "foo", "abs"], match_substrings=False)
blacklist.compiled  # re.compile(r'(?<=\b)(?:ab[cs]|foo)(?=\b)', re.IGNORECASE|re.UNICODE)

assert not blacklist.is_blacklisted("a foobar")
assert tuple(blacklist.filter(("good", "abc", "foobar"))) == ("good", "foobar")
assert blacklist.cleanse_text(("good abc foobar")) == "good  foobar"

blacklist = Blacklist(["abc", "foo", "abs"], match_substrings=True)
blacklist.compiled  # re.compile(r'(?:ab[cs]|foo)', re.IGNORECASE|re.UNICODE)

assert blacklist.is_blacklisted("a foobar")
assert tuple(blacklist.filter(("good", "abc", "foobar"))) == ("good",)
assert blacklist.cleanse_text(("good abc foobar")) == "good  bar"

Whitelist

Similar methods are available for the Whitelist object:

from retrie.retrie import Whitelist

whitelist = Whitelist(["abc", "foo", "abs"], match_substrings=False)
whitelist.compiled  # re.compile(r'(?<=\b)(?:ab[cs]|foo)(?=\b)', re.IGNORECASE|re.UNICODE)

assert not whitelist.is_whitelisted("a foobar")
assert tuple(whitelist.filter(("bad", "abc", "foobar"))) == ("abc",)
assert whitelist.cleanse_text(("good abc foobar")) == "abc"

whitelist = Whitelist(["abc", "foo", "abs"], match_substrings=True)
whitelist.compiled  # re.compile(r'(?:ab[cs]|foo)', re.IGNORECASE|re.UNICODE)

assert whitelist.is_whitelisted("a foobar")
assert tuple(whitelist.filter(("bad", "abc", "foobar"))) == ("abc", "foobar")
assert whitelist.cleanse_text(("good abc foobar")) == "abcfoo"

Replacer

The Replacer object can search & replace occurrences of replacement_mapping.keys() with corresponding values.

from retrie.retrie import Replacer

replacer = Replacer(
    replacement_mapping=dict(zip(["abc", "foo", "abs"], ["new1", "new2", "new3"])),
    match_substrings=True,
)
replacer.compiled  # re.compile(r'(?:ab[cs]|foo)', re.IGNORECASE|re.UNICODE)
assert replacer.replace("ABS ...foo... foobar") == "new3 ...new2... new2bar"

replacer = Replacer(
    replacement_mapping=dict(zip(["abc", "foo", "abs"], ["new1", "new2", "new3"])),
    match_substrings=False,
)
assert replacer.replace("ABS ...foo... foobar") == "new3 ...new2... foobar"

replacer = Replacer(
    replacement_mapping=dict(zip(["abc", "foo", "abs"], ["new1", "new2", "new3"])),
    match_substrings=False,
    re_flags=None,
)
assert replacer.replace("ABS ...foo... foobar") == "ABS ...new2... foobar"

replacer = Replacer(
    replacement_mapping=dict(zip(["abc", "foo", "abs"], ["new1", "new2", "new3"])),
    match_substrings=False,
    word_boundary=" ",
)
assert replacer.replace(". ABS ...foo... foobar") == ". new3 ...foo... foobar"

Development

gitmoji pre-commit

Create a virtual environment.

python -m venv .venv
source .venv/bin/activate

Get ready to develop:

make install

This is equivalent to the following steps:

  • Install pre-commit and other continous integration dependencies in order to make commits and run tests.

    pip install -r requirements/ci.txt
    pre-commit install
    
  • With requirements installed, make lint and make test can now be run. There is also make clean, and make all which runs all three.

  • To import the package in the python environment, install the package (-e for editable installation, upon import, python will read directly from the repository).

    pip install -e .
    

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

retrie-0.1.0.tar.gz (9.3 kB view hashes)

Uploaded Source

Built Distribution

retrie-0.1.0-py2.py3-none-any.whl (7.4 kB view hashes)

Uploaded Python 2 Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page