f76a33
#! /usr/bin/env python3
f76a33
f76a33
from __future__ import print_function
f76a33
f76a33
import re
f76a33
f76a33
try:
f76a33
    basestring
f76a33
except NameError:
f76a33
    basestring = str
f76a33
f76a33
# ---------------------------------------------------------- Regex Match()
f76a33
# beware, stupid python interprets backslashes in replace-parts only partially!
f76a33
class MatchReplace:
f76a33
    """ A MatchReplace is a mix of a Python Pattern and a Replace-Template """
f76a33
    def __init__(self, matching, template, count = 0, flags = None):
f76a33
        """ setup a substition from regex 'matching' into 'template',
f76a33
            the replacement count default of 0 will replace all occurrences.
f76a33
            The first argument may be a Match object or it is a string that
f76a33
            will be turned into one by using Match(matching, flags). """
f76a33
        self.template = template
f76a33
        MatchReplace.__call__(self, matching, template, count, flags)
f76a33
    def __call__(self, matching, template = None, count = 0, flags = None):
f76a33
        """ other than __init__ the template may be left off to be unchanged"""
f76a33
        if isinstance(count, basestring): # count/flags swapped over?
f76a33
            flags = count; count = 0
f76a33
        if isinstance(matching, Match):
f76a33
            self.matching = matching
f76a33
        else:
f76a33
            self.matching = Match()(matching, flags) ## python 2.4.2 bug
f76a33
        if template is not None:
f76a33
            self.template = template
f76a33
        self.count = count
f76a33
    def __and__(self, string):
f76a33
        """ z = MatchReplace('foo', 'bar') & 'foo'; assert z = 'bar' """
f76a33
        text, self.matching.replaced = \
f76a33
              self.matching.regex.subn(self.template, string, self.count)
f76a33
        return text
f76a33
    def __rand__(self, string):
f76a33
        """ z = 'foo' & Match('foo') >> 'bar'; assert z = 'bar' """
f76a33
        text, self.matching.replaced = \
f76a33
              self.matching.regex.subn(self.template, string, self.count)
f76a33
        return text
f76a33
    def __iand__(self, string):
f76a33
        """ x = 'foo' ; x &= Match('foo') >> 'bar'; assert x == 'bar' """
f76a33
        string, self.matching.replaced = \
f76a33
                self.matching.regex.subn(self.template, string, self.count)
f76a33
        return string
f76a33
    def __rshift__(self, count):
f76a33
        " shorthand to set the replacement count: Match('foo') >> 'bar' >> 1 "
f76a33
        self.count = count ; return self
f76a33
    def __rlshift__(self, count):
f76a33
        self.count = count ; return self
f76a33
f76a33
class Match:
f76a33
    """ A Match is actually a mix of a Python Pattern and MatchObject """
f76a33
    def __init__(self, pattern = None, flags = None):
f76a33
        """ flags is a string: 'i' for case-insensitive etc.; it is just
f76a33
        short for a regex prefix: Match('foo','i') == Match('(?i)foo') """
f76a33
        Match.__call__(self, pattern, flags)
f76a33
    def __call__(self, pattern, flags = None):
f76a33
        assert isinstance(pattern, str) or pattern is None
f76a33
        assert isinstance(flags, str) or flags is None
f76a33
        self.replaced = 0 # set by subn() inside MatchReplace
f76a33
        self.found = None # set by search() to a MatchObject
f76a33
        self.pattern = pattern
f76a33
        if pattern is not None:
f76a33
            if flags:
f76a33
                self.regex = re.compile("(?"+flags+")"+self.pattern)
f76a33
            else:
f76a33
                self.regex = re.compile(self.pattern)
f76a33
        return self
f76a33
    def __repr__(self):
f76a33
        return self.pattern
f76a33
    def __truth__(self):
f76a33
        return self.found is not None
f76a33
    def __and__(self, string):
f76a33
        self.found = self.regex.search(string)
f76a33
        return self.__truth__()
f76a33
    def __rand__(self, string):
f76a33
        self.found = self.regex.search(string)
f76a33
        return self.__truth__()
f76a33
    def __rshift__(self, template):
f76a33
        return MatchReplace(self, template)
f76a33
    def __rlshift__(self, template):
f76a33
        return MatchReplace(self, template)
f76a33
    def __getitem__(self, index):
f76a33
        return self.group(index)
f76a33
    def group(self, index):
f76a33
        assert self.found is not None
f76a33
        return self.found.group(index)
f76a33
    def finditer(self, string):
f76a33
        return self.regex.finditer(string)
f76a33
f76a33
if __name__ == "__main__":
f76a33
    # matching:
f76a33
    if "foo" & Match("oo"):
f76a33
        print("oo")
f76a33
    x = Match()
f76a33
    if "foo" & x("(o+)"):
f76a33
        print(x[1])
f76a33
    # replacing:
f76a33
    y = "fooboo" & Match("oo") >> "ee"
f76a33
    print(y)
f76a33
    r = Match("oo") >> "ee"
f76a33
    print("fooboo" & r)
f76a33
    s = MatchReplace("oo", "ee")
f76a33
    print("fooboo" & s)