Our friendly friend Pete is really a nice person, but he tends to be rather... Inappropriate.

And possibly loud, if given enough ethanol and free rein, so we ask you to write a function that should take its not always "clean" speech and cover as much as possible of it, in order not to offend some more sensible spirits.

For example, given an input like
```
What the hell am I doing here? And where is my wallet? PETE SMASH!
```
You are expected to turn it into something like:
```
W**t t*e h**l am i d***g h**e? A*d w***e is my w****t? P**e s***h!
```
In case you didn't figure out the rules yet: any words longer than 2 characters need to have its "inside" (meaning every character which is not the first or the last) changed into `*`;  as we do not want Pete to scream too much, every uppercase letter which is not at the beginning of the string or coming after a punctuation mark among [".","!","?"] needs to be put to lowercase; spaces and other punctuation marks can be ignored.

Conversely, you need to be sure that the start of each sentence has a capitalized word at the beginning. Sentences are divided by the aforementioned punctuation marks.

Finally, the function will take an additional parameter consisting of an array/list of allowed words (upper or lower case) which are not to be replaced (the match has to be case insensitive).

Extra cookies if you can do it all in some efficient way and/or using our dear regexes ;)

**Note:** Absolutely not related to [a certain codewarrior I know](http://www.codewars.com/users/petegarvin1) :p

Difficulty: introductory

Starter code:

def pete_talk(speech, ok = []):
	

Solutions:
import re

PATTERN = re.compile(r'(?P<first>(?:(?<=[.!?] )|^)\w+)|(?P<other>\w+)')

def pete_talk(speech,ok=[]):

    def watchYourMouth(m):
        w = (m.group("first") or m.group("other")).lower()
        if w not in ok and len(w) > 1: w = w[0] + '*'*(len(w)-2) + w[-1]
        if m.group("first"): w = w.capitalize()
        return w
    
    ok = set(map(str.lower, ok))
    return PATTERN.sub(watchYourMouth, speech)

import re

def pete_talk(speech, ok=()):
    ok = {word.lower() for word in ok}
    def sub(m):
        s = m.group()
        if s in ok:
            return s
        return s[0] + '*' * (len(s) - 2) + s[-1]
    return re.sub(
        r'[a-z][^.?!]+',
        lambda m: re.sub(r'\w{3,}', sub, m.group()).capitalize(),
        speech.lower(),
    )

import re

def pete_talk(speech, ok = []):
    ok = [i.lower() for i in ok]
    def repl(m):
        if m.group('word') not in ok:
            return m.group('word')[0] + '*' * len(m.group('reppart')) + m.group('word')[-1]
        else: return m.group('word')
            
    replaced = re.sub('(?P<word>[\w](?P<reppart>[\w]+)[\w])', repl, speech.lower())
    capitalized = re.sub('(?P<sent>[.!?]+\s*|\A\s*)(?P<word>\s*[a-z])', lambda m: m.group('sent') + m.group('word').capitalize(), replaced)
    return capitalized

import re
def pete_talk(*args):
    speech = args[0].lower()
    permitted = args[1] if len(args) == 2 else []
    speech = re.sub('([!\?\.] )(\w+)', upper, speech)
    speech = re.sub('^(\w)', upper, speech)
    speech = re.sub('(\w{3,})', lambda match: bleep(match, permitted), speech)
    return speech

def bleep(match, perm):
    st = match.group(1)
    bleeped = st[0] + ('*' * (len(st) - 2)) + st[-1]
    return bleeped if st.lower() not in [x.lower() for x in perm] else st

def upper(match):
    groups = list(match.groups())
    groups[-1] = groups[-1].capitalize()
    return ''.join(groups)

def pete_talk(speech, ok = []):
    from re import split, sub
    ok = [x.lower() for x in ok]
    
    def add_stars(strng):
        x = strng.group(0)

        if x.lower() not in ok:
            return x[0] + "*"*(len(x) - 2) + x[-1]
        else:
            return x
    
    def process(s):
        s = sub("^([a-z])", lambda x: x.group(0).upper(), s)
        s = sub("(?<=.{1})\w", lambda x: x.group(0).lower(), s)
        s = sub("[a-zA-Z]{3,}", add_stars, s)
        return s

    return " ".join(process(s) for s in split("(?<=[.!?])\ ", speech))

import re
def pete_talk(s,ok=[]):
    ok = list(map(lambda x:x.lower(),ok))
    return re.sub(r'((?<=^)|(?<=[?.!] ))\w',lambda x:x.group(0).upper(),' '.join([(i[0]+'*'*(len(i)-2-int(i[-1]in'!.,?;:'))+i[-[1,2][i[-1]in'!.,;?:']:])if[i,i[:-1]][i[-1]in'!.,;?:']not in ok and len(i)>2else i for i in s.lower().split()]))

import re
def pete_talk(speech, ok = []):
    ok = {v.lower() for v in ok}
    def repl(Match):
        s = Match[0]
        i = Match.start()
        
        
        if i == 0 or (i >= 2 and speech[i - 2] in '.!?'):
            s = s.capitalize()
        else:
            s = s.lower()
        n = len(s)
        if n <= 2 or s.lower() in ok:
            return s
        return s[0] + '*' * (n - 2) + s[-1]
    return re.sub('\w+', repl, speech)

import re

def pete_talk(speech, ok=()):
    oks = [w.lower() for w in ok]
    upper_first = re.sub('^[a-z]', lambda c: c.group().upper(), speech, 1)
    lower2uppercased = re.sub('[A-Z]{2,}|[.!?] [a-z]', lambda w: w.group().title(), upper_first)
    lower_punc = re.sub(r'[^.!?] [A-Z]', lambda w: w.group().lower(), lower2uppercased)

    def xx(g):
        w = g.group()
        return f'{w[0]}{(len(w)-2) * "*"}{w[-1]}' if w.lower() not in oks else w

    long_words = re.sub('[a-zA-Z]{2,}', xx, lower_punc)

    return long_words

import re

def pete_talk(s, a=None):
    a = {x.lower() for x in a or []}
    def f(x):
        x = x[0]
        return x if x.lower() in a else x[0] + "*" * (len(x) - 2) + x[-1] * (len(x) > 1)
    return "".join(x.capitalize() for x in re.split(r"([!?.] ?)", re.sub(r"\w+", f, s)))

from re import sub

capital = lambda x: x.group().capitalize()
censor = lambda x: (x[0] + '*'*(len(x) - 2) + x[-1])

def pete_talk(speech, ok=[]):
    okay = set(map(str.lower, ok)).__contains__
    check = lambda x: x.group() if okay(x.group().lower()) else censor(x.group())
    return sub(r"[\w\s*:,;]+(?:[\.?!](?:\s|$)|$)", capital, sub(r"\w{3,}", check, speech))