get_close_matches is such a godsend. I've already used it this morning to deal with matching up 2 lists with about 100 things in each.
One trick I've found is to use it in both directions and then only using results that agree both ways.
Something like this (very terse version):
closest_or_none = lambda l, options: (difflib.get_close_matches(l, options, n=1) or [None])[0]
dir1 = [(l, closest_or_none(l, list2)) for l in list1]
dir2 = [(closest_or_none(l, list1), l) for l in list2]
one_to_one = set(dir1).intersection(set(dir2))
Interested to hear how you approached the rotation thing.
Rough summary: I generated best fit lines from the alignment of the letters. You know the lines on the receipt consist of straight-aligned letters, so you can calculate lines based on that. I then calculated the average slope of all those lines and then used that average to base the rotation calculation on.
One trick I've found is to use it in both directions and then only using results that agree both ways.
Something like this (very terse version):
Interested to hear how you approached the rotation thing.