How to determine whether a Python string contains an emoji?
<p>I've seen previous responses to this question, but none of them are recent and none of them are working for me in Python 3. I have a list of strings, and I simply want to identify which ones contain emoji. What's the fastest way to do this?</p>

<p>To be more specific, I have a lengthy list of email subject lines from AB tests, and I'm trying to determine which subject lines contained emoji.</p>

<p><a href="http://stackoverflow.com/questions/28290240/python-2-7-detect-emoji-from-text/28327594#28327594">this link</a> and <a href="http://stackoverflow.com/questions/38730560/is-there-a-specific-range-of-unicode-code-points-which-can-be-checked-for-emojis">this link</a> both count Â© and other common characters as emoji. Also the former has minor mistakes and the latter still doesn't appear to work.</p>

<p>Here's an implementation that errs on the conservative side using <a href="ftp://ftp.unicode.org/Public/emoji/3.0/emoji-data.txt" rel="nofollow">this newer data</a> and <a href="http://www.unicode.org/reports/tr51/" rel="nofollow">this documentation</a>. It only considers code points that are marked with the unicode property <code>Emoji_Presentation</code> (which means it's definitely an emoji), or code points marked only with the property <code>Emoji</code> (which means it defaults to text but it <em>could</em> be an emoji), that are followed by a special variation selector code point <code>fe0f</code> that says to default to an emoji instead. The reason I say this is conservative is because certain systems aren't as picky about the <code>fe0f</code> and will treat characters as emoji wherever they can (read more about this <a href="http://www.unicode.org/reports/tr51/#Presentation_Style" rel="nofollow">here</a>).</p>

<pre><code>import re
from collections import defaultdict


def parse_line(line):
    """Return a pair (property, codepoints) where property is a string and
       codepoints is a set of int unicode code points"""
    pat = r'([0-9A-Z]+)(\.\.[0-9A-Z]+)? + ; +(\w+) + #.*'
    match = re.match(pat, line)
    assert match

    codepoints = set()

    start = int(match.group(1), 16)

    if match.group(2):
        trimmed = match.group(2)[2:]
        end = int(trimmed, 16) + 1
    else:
        end = start + 1

    for cp in range(start, end):
        codepoints.add(cp)

    return (match.group(3), codepoints)


def parse_emoji_data():
    """Return a dictionary mapping properties to code points"""
    result = defaultdict(set)
    with open('emoji-data.txt', mode='r', encoding='utf-8') as f:
        for line in f:
            if '#' != line[0] and len(line.strip()) &gt; 0:
                property, cp = parse_line(line)
                result[property] |= cp
    return result


def test_parse_emoji_data():
    sets = parse_emoji_data()
    sizes = {
        'Emoji': 1123,
        'Emoji_Presentation': 910,
        'Emoji_Modifier': 5,
        'Emoji_Modifier_Base': 83,
    }
    for k, v in sizes.items():
        assert len(sets[k]) == v


def contains_emoji(text):
    """
    Return true if the string contains either a code point with the
    `Emoji_Presentation` property, or a code point with the `Emoji`
    property that is followed by \uFE0F
    """
    sets = parse_emoji_data()
    for i, ch in enumerate(text):
        if ord(ch) in sets['Emoji_Presentation']:
            return True
        elif ord(ch) in sets['Emoji']:
            if len(text) &gt; i+1 and text[i+1] == '\ufe0f':
                return True
    return False

test_parse_emoji_data()
assert not contains_emoji('hello')
assert not contains_emoji('hello :) :D 125% #%&amp;*(@#%&amp;!@(^*(')
assert contains_emoji('here is a smiley \U0001F601 !!!')
</code></pre>

<p>To run this you need <a href="ftp://ftp.unicode.org/Public/emoji/3.0/emoji-data.txt" rel="nofollow">ftp://ftp.unicode.org/Public/emoji/3.0/emoji-data.txt</a> in the working directory.</p>

<p>Once the regex module supports emoji properties it will be easier to use that instead.</p>

python emoji