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: EASY

Starter code:
def pete_talk(speech, ok = []):
	

Solutions:
import re
PATTERN = re.compile('(?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('[a-z][^.?!]+', lambda m: re.sub('\\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('((?<=^)|(?<=[?.!] ))\\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) > 2 else 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('[^.!?] [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('([!?.] ?)', re.sub('\\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('[\\w\\s*:,;]+(?:[\\.?!](?:\\s|$)|$)', capital, sub('\\w{3,}', check, speech))