Write a function that, given a string of text (possibly with punctuation and line-breaks),
returns an array of the top-3 most occurring words, in descending order of the number of occurrences.

Assumptions:
------------

- A word is a string of letters (A to Z) optionally containing one or more apostrophes (') in ASCII. (No need to handle fancy punctuation.)
- Matches should be case-insensitive, and the words in the result should be lowercased.
- Ties may be broken arbitrarily.
- If a text contains fewer than three unique words, then either the top-2 or top-1 words should be returned, or an empty array if a text contains no words.

Examples:
------------

```
top_3_words("In a village of La Mancha, the name of which I have no desire to call to
mind, there lived not long since one of those gentlemen that keep a lance
in the lance-rack, an old buckler, a lean hack, and a greyhound for
coursing. An olla of rather more beef than mutton, a salad on most
nights, scraps on Saturdays, lentils on Fridays, and a pigeon or so extra
on Sundays, made away with three-quarters of his income.")
# => ["a", "of", "on"]

top_3_words("e e e e DDD ddd DdD: ddd ddd aa aA Aa, bb cc cC e e e")
# => ["e", "ddd", "aa"]

top_3_words("  //wont won't won't")
# => ["won't", "wont"]
```

```if:java
For java users, the calls will actually be in the form: `TopWords.top3(String s)`, expecting you to return a `List`.
```

Bonus points (not really, but just for fun):
------------

1. Avoid creating an array whose memory footprint is roughly as big as the input text.
2. Avoid sorting the entire array of unique words.

Difficulty: interview

Starter code:

def top_3_words(text):
	

Solutions:
from collections import Counter
import re


def top_3_words(text):
    c = Counter(re.findall(r"[a-z']+", re.sub(r" '+ ", " ", text.lower())))
    return [w for w,_ in c.most_common(3)]

import re
from collections import Counter

top_3_words=lambda t:[w for w,c in Counter(re.findall("'*[a-z][a-z']*",t.lower())).most_common(3)]

import re
from collections import Counter

def top_3_words(text):
    words = re.findall(r"[a-z']*[a-z]+[a-z']*", text.lower())
    top_3 = Counter(words).most_common(3)
    return [tup[0] for tup in top_3]

from collections import Counter
import re

def top_3_words(text):
    words = re.findall(r"[a-z][a-z']*|[a-z']*[a-z]", text, re.IGNORECASE)
    topchart = Counter([word.lower() for word in words]).most_common(3)
    return [top[0] for top in topchart]

import re

def top_3_words(text):
    re_non_valid = re.compile('[^a-z\' ]')
    re_chars = re.compile('[a-z]')
    text = text.lower()
    text = ' '.join([x for x in re_non_valid.sub(' ',text).split() if re_chars.search(x)])
    words = {}
    top = {}                    # Dictionary with no more than 3 words
    for word in text.split():
        if word in words:
            words[word] += 1
        else:
            words[word] = 1
        top[word] = words[word] # Add the new word to the top
        if len(top) > 3:        # If the top is too big remove the worst word
            top.pop(min(top, key=top.get))
    return sorted(top, key=top.get, reverse=True)

from collections import Counter
from string import ascii_letters, printable

keep = ascii_letters + "'"
remove = printable.translate(str.maketrans('', '', keep))
table = str.maketrans(keep + remove, keep.lower() + ' ' * len(remove))

def top_3_words(text):
    words = (word for word in text.translate(table).split() if set(word) != {"'"})
    return [word for word, freq in Counter(words).most_common(3)]

from operator import itemgetter

def top_3_words(text):
    text0 = "".join([ c if c in "abcdefghijklmnopqrstuvwxyz'" else " " for c in text.lower() ])#change rubbish to " "
    check_dict = {} #create dictionary
    text0 = text0.split() #convert text to a list
    for x in text0: #remove lone "'"s
        if not any(i.isalpha() for i in x):
            text0.pop(text0.index(x))
    for x in text0:
        if x in check_dict:
            check_dict[x] += 1 #count each use
        else:
            check_dict.update({x: 1}) #create keys and values
    top_3_list = list(sorted(list(check_dict.items()), key = itemgetter(1), reverse = True)[:3]) #sorts
    return list(map(itemgetter(0), top_3_list))#returns only the word


from string import punctuation

def top_3_words(text):
    for p in punctuation: 
        if p != "'": text = text.replace(p, " ")
    count = {}
    for w in text.lower().split():
        if w.strip(punctuation) == '':
            pass
        elif w in count.keys():
            count[w] += 1
        else:
            count[w] = 1
    lcount = [(w,c) for w,c in count.items()]
    lcount.sort(key=lambda x: x[1], reverse=True)
    return [x[0] for x in lcount[:3]]

from collections import Counter as C
from re import sub as s
from string import punctuation as p
def top_3_words(__):
    __ = s('[{}]'.format(p.replace("'",'')),' ',__).lower() 
    return list(filter(lambda c: c.replace("'",'').isalnum(),(_[0] for _ in C(__.split()).most_common(3))))

import re
def top_3_words(text):
    panctuation = '_\''
    list_word = re.findall(r'[a-z0-9A-Z\']+',text.lower())
    result = []
    dict1 = {}
    for word in list_word:
        if word and word != "'" and word != "'''":
            if word in dict1:
                dict1[word]+=1
            else:
                dict1[word] = 1
    result = sorted(list(dict1.items()), reverse=True, key=lambda x: x[1])
    result = result[:3] if len(result)>3 else result
    return [res[0] for res in result]