Recuperación del manejo de python 3.6 de re.sub () con coincidencias de longitud cero en python 3.7

l manejo de coincidencias de longitud cero ha cambiado con Python 3.7. Considere lo siguiente con python 3.6 (y anterior):

>>> import re
>>> print(re.sub('a*', 'x', 'bac'))
xbxcx
>>> print(re.sub('.*', 'x', 'bac'))
x

Obtenemos lo siguiente con Python 3.7:

>>> import re
>>> print(re.sub('a*', 'x', 'bac'))
xbxxcx
>>> print(re.sub('.*', 'x', 'bac'))
xx

Entiendo que este es el comportamiento estándar de PCRE. Además, re.finditer () parece haber detectado siempre la coincidencia adicional:

>>> for m in re.finditer('a*', 'bac'):
...     print(m.start(0), m.end(0), m.group(0))
...
0 0
1 2 a
2 2
3 3

icho esto, estoy interesado en recuperar el comportamiento de Python 3.6 (esto es para un proyecto de pasatiempo que implementased en python).

Puedo venir con la siguiente solución:

def sub36(regex, replacement, string):

    compiled = re.compile(regex)

    class Match(object):
        def __init__(self):
            self.prevmatch = None
        def __call__(self, match):
            try:
                if match.group(0) == '' and self.prevmatch and match.start(0) == self.prevmatch.end(0):
                    return ''
                else:
                    return re._expand(compiled, match, replacement)
            finally:
                self.prevmatch = match

    return compiled.sub(Match(), string)

lo que da

>>> print(re.sub('a*', 'x', 'bac'))
xbxxcx
>>> print(sub36('a*', 'x', 'bac'))
xbxcx
>>> print(re.sub('.*', 'x', 'bac'))
xx
>>> print(sub36('.*', 'x', 'bac'))
x

Sin embargo, esto parece muy elaborado para estos ejemplos.

Cuál sería la forma correcta de implementar el comportamiento de python 3.6 para las coincidencias de longitud cero re.sub () con python 3.7?

Respuestas a la pregunta(3)

Su respuesta a la pregunta