【问题标题】:Remove Emoji's from multilingual Unicode text从多语言 Unicode 文本中删除表情符号
【发布时间】:2019-01-17 23:28:44
【问题描述】:

我正在尝试从 Unicode 文本中删除 just 表情符号。我尝试了各种方法described in another Stack Overflow post,但这些方法都没有完全删除所有表情符号/笑脸。例如:

解决方案 1:

def remove_emoji(self, string):
    emoji_pattern = re.compile("["
                           u"\U0001F600-\U0001F64F"  # emoticons
                           u"\U0001F300-\U0001F5FF"  # symbols & pictographs
                           u"\U0001F680-\U0001F6FF"  # transport & map symbols
                           u"\U0001F1E0-\U0001F1FF"  # flags (iOS)
                           u"\U00002702-\U000027B0"
                           u"\U000024C2-\U0001F251"
                           "]+", flags=re.UNICODE)
    return emoji_pattern.sub(r'', string)

留在 ????在以下示例中:

Input: తెలంగాణ రియల్ ఎస్టేట్ ????????
Output: తెలంగాణ రియల్ ఎస్టేట్ ????

另一个尝试,解决方案2:

def deEmojify(self, inputString):
    returnString = ""
    for character in inputString:
        try:
            character.encode("ascii")
            returnString += character
        except UnicodeEncodeError:
            returnString += ''
    return returnString

导致删除任何非英文字符:

 Input: ????Testరియల్ ఎస్టేట్ A.P&T.S. ????????????????
 Output: Test  A.P&T.S. 

它不仅删除了所有表情符号,还删除了非英文字符,因为character.encode("ascii");我的非英语输入无法编码为 ASCII。

有没有办法从国际 Unicode 文本中正确删除表情符号?

【问题讨论】:

  • 新的表情符号会定期添加到 Unicode 标准中;您需要不断更新这些正则表达式。
  • 第一个示例中留下的表情符号是 U+1F91D,added in Unicode 9.0。而Unicode 10.0Unicode 11.0 再次扩大了名单。我确定 12.0 版需要更多更新。
  • 谢谢,我会记住的。

标签: python regex string unicode emoji


【解决方案1】:

正则表达式已过时。它似乎涵盖了定义到 Unicode 8.0 的表情符号(因为 U+1F91D HANDSHAKE 是在 Unicode 9.0 中添加的)。另一种方法只是将强制编码为 ASCII 的一种非常低效的方法,这在删除 Emoji 时很少需要(使用text.encode('ascii', 'ignore').decode('ascii') 可以更轻松有效地实现)。

如果您需要更新的正则表达式,请从a package that is actively trying to keep up-to-date on Emoji 中获取;它特别支持生成这样的正则表达式:

import emoji

def remove_emoji(text):
    return emoji.get_emoji_regexp().sub(u'', text)

该软件包目前是 Unicode 11.0 的最新版本,并且具有可快速更新到未来版本的基础架构。您的项目所要做的就是在有新版本时进行升级。

使用您的示例输入进行演示:

>>> print(remove_emoji(u'తెలంగాణ రియల్ ఎస్టేట్ ??'))
తెలంగాణ రియల్ ఎస్టేట్ 
>>> print(remove_emoji(u'?Testరియల్ ఎస్టేట్ A.P&T.S. ????'))
Testరియల్ ఎస్టేట్ A.P&T.S. 

请注意,正则表达式适用于 Unicode 文本,对于 Python 2,请确保您已从 str 解码到 unicode,对于 Python 3,从 bytesstr 第一

如今,表情符号是复杂的野兽。以上将删除完整、有效的表情符号。如果您有“不完整”的 Emoji 组件,例如 skin-tone codepoints(仅与 特定 Emoji 结合使用),那么删除这些组件会遇到更多麻烦。肤色代码点很简单(之后只需删除这 5 个代码点),但有一个 whole host of combinations 由无辜字符组成,例如 ♀ U+2640 FEMALE SIGN 或 ♂ U+2642 MALE SIGN 以及 variant selectorsU+200D ZERO-WIDTH JOINER其他上下文中也有特定含义,你不能只是将它们正则表达式,除非你不介意使用梵文、卡纳达语或 CJK 表意文字来破坏文本,以仅举几个例子。

也就是说,以下 Unicode 11.0 代码点可能可以安全删除(基于过滤 Emoji_Component Emoji-data designation):

20E3          ;  (⃣)     combining enclosing keycap
FE0F          ; ()        VARIATION SELECTOR-16
1F1E6..1F1FF  ; (?..?)  regional indicator symbol letter a..regional indicator symbol letter z
1F3FB..1F3FF  ; (?..?)  light skin tone..dark skin tone
1F9B0..1F9B3  ; (?..?) red-haired..white-haired
E0020..E007F  ; (?..?)      tag space..cancel tag

可以通过创建一个新的正则表达式来匹配这些:

import re
try:
    uchr = unichr  # Python 2
    import sys
    if sys.maxunicode == 0xffff:
        # narrow build, define alternative unichr encoding to surrogate pairs
        # as unichr(sys.maxunicode + 1) fails.
        def uchr(codepoint):
            return (
                unichr(codepoint) if codepoint <= sys.maxunicode else
                unichr(codepoint - 0x010000 >> 10 | 0xD800) +
                unichr(codepoint & 0x3FF | 0xDC00)
            )
except NameError:
    uchr = chr  # Python 3

# Unicode 11.0 Emoji Component map (deemed safe to remove)
_removable_emoji_components = (
    (0x20E3, 0xFE0F),             # combining enclosing keycap, VARIATION SELECTOR-16
    range(0x1F1E6, 0x1F1FF + 1),  # regional indicator symbol letter a..regional indicator symbol letter z
    range(0x1F3FB, 0x1F3FF + 1),  # light skin tone..dark skin tone
    range(0x1F9B0, 0x1F9B3 + 1),  # red-haired..white-haired
    range(0xE0020, 0xE007F + 1),  # tag space..cancel tag
)
emoji_components = re.compile(u'({})'.format(u'|'.join([
    re.escape(uchr(c)) for r in _removable_emoji_components for c in r])),
    flags=re.UNICODE)

然后更新上面的remove_emoji()函数来使用它:

def remove_emoji(text, remove_components=False):
    cleaned = emoji.get_emoji_regexp().sub(u'', text)
    if remove_components:
        cleaned = emoji_components.sub(u'', cleaned)
    return cleaned

【讨论】:

  • 感谢您的回答。对于输入HMDA plot sales Agents???,它给出HMDA plot sales Agents? 。我猜仍然没有涵盖所有的表情符号。
  • @ascii_walker:这是一个未配对的 U+1F3FC EMOJI MODIFIER FITZPATRICK TYPE-3 代码点。这本身是否是一个表情符号还有待商榷。
  • @ascii_walker: 很明显,emoji 包并不认为它是 emoji;如果您将其与支持表情符号配对,它将被删除。例如,?? 被删除,因为它是 U+1F91F U+1F3FC 的配对,这就是该模式的使用方式。
  • 同样对于这个输入,它不会删除任何表情符号(不确定它们是否是表情符号) 输入:Plot?Flat?House?Sale?Advt 输出:Plot?Flat?House?Sale?Advt
  • @ascii_walker:对,我假设是 Python 3(Python 2.7 非常接近生命终结,你真的应该考虑升级!)。正则表达式针对 Unicode 文本,处理正则表达式中的表情符号,因为 UTF-8 序列打开了另一个巨大的蠕虫罐。我今天不去那里。
【解决方案2】:

如果您使用 regex 库而不是 re 库,您可以访问 Unicode 属性,那么您可以将函数更改为

def remove_emoji(self, string):
    emoji_pattern = re.compile("[\P{L}&&\P{D}&&\P{Z}&&\P{M}]", flags=re.UNICODE)
    return emoji_pattern.sub(r'', string)

这将保留所有字母、数字、分隔符和标记(重音)

【讨论】:

  • 这仍然不够。首先,您忘记了\P{P}SmSm 也应该没问题;表情符号主要是SoSk 类别符号。除了那些不是的; emoji.UNICODE_EMOJI 映射中的表情符号序列属于 Cf、Cn、Ll、Me、Mn、Nd、Pd、Po、Sk、Sm 和 So 类别,因此您的模式实际上会保留一些 Emoji.
  • 请注意,许多表情符号是由代码点的组合形成的。例如,'\U0001f477\U0001f3ff\u200d\u2640\ufe0f'one 表情符号:??‍♀️。您的正则表达式将保留最后一个代码点,因此 ♀️。这可能会让人感到困惑。
  • 如果我没记错的话,最新版本的 Unicode 有一个 emoji 属性,但我不知道它涵盖了哪些代码点
  • Unicode 11 有such Emoji-related properties,但您仍然有可能留下Emoji_Component 代码点。 而且它们以前不是 UCD 的一部分。
  • 另见the full list of what codepoint has what Emoji property。但是请注意,该属性非常无用。数字具有属性,#* 也是如此。
猜你喜欢
  • 2021-04-11
  • 2018-12-15
  • 1970-01-01
  • 2017-10-09
  • 1970-01-01
  • 2017-08-23
  • 1970-01-01
  • 2020-03-28
  • 1970-01-01
相关资源
最近更新 更多