1#!/usr/local/bin/python3.8
2# -*- coding: utf-8 -*-
3# @creator (C) 2003 Guido U. Draheim
4# @license http://creativecommons.org/licenses/by-nc-sa/2.0/de/
5
6from __future__ import print_function
7
8import re
9
10try:
11    basestring
12except NameError:
13    basestring = str
14
15# ---------------------------------------------------------- Regex Match()
16# beware, stupid python interprets backslashes in replace-parts only partially!
17class MatchReplace:
18    """ A MatchReplace is a mix of a Python Pattern and a Replace-Template """
19    def __init__(self, matching, template, count = 0, flags = None):
20        """ setup a substition from regex 'matching' into 'template',
21            the replacement count default of 0 will replace all occurrences.
22            The first argument may be a Match object or it is a string that
23            will be turned into one by using Match(matching, flags). """
24        self.template = template
25        MatchReplace.__call__(self, matching, template, count, flags)
26    def __call__(self, matching, template = None, count = 0, flags = None):
27        """ other than __init__ the template may be left off to be unchanged"""
28        if isinstance(count, basestring): # count/flags swapped over?
29            flags = count; count = 0
30        if isinstance(matching, Match):
31            self.matching = matching
32        else:
33            self.matching = Match()(matching, flags) ## python 2.4.2 bug
34        if template is not None:
35            self.template = template
36        self.count = count
37    def __and__(self, string):
38        """ z = MatchReplace('foo', 'bar') & 'foo'; assert z = 'bar' """
39        text, self.matching.replaced = \
40              self.matching.regex.subn(self.template, string, self.count)
41        return text
42    def __rand__(self, string):
43        """ z = 'foo' & Match('foo') >> 'bar'; assert z = 'bar' """
44        text, self.matching.replaced = \
45              self.matching.regex.subn(self.template, string, self.count)
46        return text
47    def __iand__(self, string):
48        """ x = 'foo' ; x &= Match('foo') >> 'bar'; assert x == 'bar' """
49        string, self.matching.replaced = \
50                self.matching.regex.subn(self.template, string, self.count)
51        return string
52    def __rshift__(self, count):
53        " shorthand to set the replacement count: Match('foo') >> 'bar' >> 1 "
54        self.count = count ; return self
55    def __rlshift__(self, count):
56        self.count = count ; return self
57
58class Match:
59    """ A Match is actually a mix of a Python Pattern and MatchObject """
60    def __init__(self, pattern = None, flags = None):
61        """ flags is a string: 'i' for case-insensitive etc.; it is just
62        short for a regex prefix: Match('foo','i') == Match('(?i)foo') """
63        Match.__call__(self, pattern, flags)
64    def __call__(self, pattern, flags = None):
65        assert isinstance(pattern, str) or pattern is None
66        assert isinstance(flags, str) or flags is None
67        self.replaced = 0 # set by subn() inside MatchReplace
68        self.found = None # set by search() to a MatchObject
69        self.pattern = pattern
70        if pattern is not None:
71            if flags:
72                self.regex = re.compile("(?"+flags+")"+self.pattern)
73            else:
74                self.regex = re.compile(self.pattern)
75        return self
76    def __repr__(self):
77        return self.pattern
78    def __truth__(self):
79        return self.found is not None
80    def __and__(self, string):
81        self.found = self.regex.search(string)
82        return self.__truth__()
83    def __rand__(self, string):
84        self.found = self.regex.search(string)
85        return self.__truth__()
86    def __rshift__(self, template):
87        return MatchReplace(self, template)
88    def __rlshift__(self, template):
89        return MatchReplace(self, template)
90    def __getitem__(self, index):
91        return self.group(index)
92    def group(self, index):
93        assert self.found is not None
94        return self.found.group(index)
95    def finditer(self, string):
96        return self.regex.finditer(string)
97
98if __name__ == "__main__":
99    # matching:
100    if "foo" & Match("oo"):
101        print("oo")
102    x = Match()
103    if "foo" & x("(o+)"):
104        print(x[1])
105    # replacing:
106    y = "fooboo" & Match("oo") >> "ee"
107    print(y)
108    r = Match("oo") >> "ee"
109    print("fooboo" & r)
110    s = MatchReplace("oo", "ee")
111    print("fooboo" & s)
112