如何从输入中过滤表情符号字符,以便我可以保存在MySQL <5.5中?

Big*_*sZX 14 python mysql django utf-8 character-encoding

我有一个Django应用程序,它从Twitter的API获取tweet数据并将其保存在MySQL数据库中.据我所知(我仍然围绕着字符编码的细节)我在任何地方都使用UTF-8,包括MySQL编码和校对,除了当推文包含表情符号字符时,它工作正常,我理解使用四字节编码.试图保存它们会产生Django的以下警告:

/home/biggleszx/.virtualenvs/myvirtualenv/lib/python2.6/site-packages/django/db/backends/mysql/base.py:86:警告:字符串值不正确:'\ xF0\x9F\x98\xAD I ...'对于第1行的列'text'返回self.cursor.execute(query,args)

我正在使用MySQL 5.1,所以使用utf8mb4不是一个选项,除非我升级到5.5,我还不愿意(也是从我读过的,Django对此的支持还没有完全适合生产,虽然这可能不再准确).我也看到人们建议在受影响的列上使用BLOB而不是TEXT,我也不愿意这样做,因为我认为它会损害性能.

我的问题是,假设我对100%保留推文内容不太感兴趣,是否有一种方法可以过滤掉所有表情符号字符并用非多字节字符替换它们,例如古老的字符WHITE MEDIUM SMALL SQUARE (U+25FD)?我认为这是在我当前设置下保存数据的最简单方法,但如果我错过了另一个明显的解决方案,我很乐意听到它!

仅供参考,我在Ubuntu 10.04.4 LTS上使用了Python 2.6.5.sys.maxunicode是1114111,所以这是一个UCS-4版本.

谢谢阅读.

Big*_*sZX 23

所以事实证明这已经被回答了几次,我只是没有找到合适的Google-fu来找到现有的问题.

感谢Martijn Pieters,解决方案来自正则表达式世界,特别是这段代码(基于他对上面第一个链接的回答):

import re
try:
    # UCS-4
    highpoints = re.compile(u'[\U00010000-\U0010ffff]')
except re.error:
    # UCS-2
    highpoints = re.compile(u'[\uD800-\uDBFF][\uDC00-\uDFFF]')
# mytext = u'<some string containing 4-byte chars>'
mytext = highpoints.sub(u'\u25FD', mytext)
Run Code Online (Sandbox Code Playgroud)

我正在替换的角色是WHITE MEDIUM SMALL SQUARE (U+25FD),仅供参考,但可能是任何东西.

对于那些不熟悉UCS的人,像我一样,这是一个用于Unicode转换的系统,给定的Python版本将包括对UCS-2或UCS-4变体的支持,每个变体在字符支持上都有不同的上限.

通过添加此代码,字符串似乎在MySQL 5.1中保持不变.

希望这能帮助处于同样情况的其他人!


Dav*_*odo 17

我尝试了BigglesZX的解决方案,并且在阅读[表情符号的维基百科文章]后,它并没有考虑到心脏的表情符号(❤)[1]我已经看到正则表达式没有涵盖所有表情符号,同时也覆盖其他表情符号不是表情符号的unicode范围.

以下代码创建了5个正则表达式,涵盖了标准中的5个表情符号块:

emoji_symbols_pictograms = re.compile(u'[\U0001f300-\U0001f5fF]')
emoji_emoticons = re.compile(u'[\U0001f600-\U0001f64F]')
emoji_transport_maps = re.compile(u'[\U0001f680-\U0001f6FF]')
emoji_symbols = re.compile(u'[\U00002600-\U000026FF]')
emoji_dingbats = re.compile(u'[\U00002700-\U000027BF]')
Run Code Online (Sandbox Code Playgroud)

这些块可以合并为三个块(UCS-4):

emoji_block0 = re.compile(u'[\U00002600-\U000027BF]')
emoji_block1 = re.compile(u'[\U0001f300-\U0001f64F]')
emoji_block2 = re.compile(u'[\U0001f680-\U0001f6FF]')
Run Code Online (Sandbox Code Playgroud)

它们在UCS-2中的等价物是:

emoji_block0 = re.compile(u'[\u2600-\u27BF]')
emoji_block1 = compile(u'[\uD83C][\uDF00-\uDFFF]')
emoji_block1b = compile(u'[\uD83D][\uDC00-\uDE4F]')
emoji_block2 = re.compile(u'[\uD83D][\uDE80-\uDEFF]')
Run Code Online (Sandbox Code Playgroud)

最后,我们可以将所有案例一起定义为单个正则表达式:

import re
try:
    # UCS-4
    highpoints = re.compile(u'([\U00002600-\U000027BF])|([\U0001f300-\U0001f64F])|([\U0001f680-\U0001f6FF])')
except re.error:
    # UCS-2
    highpoints = re.compile(u'([\u2600-\u27BF])|([\uD83C][\uDF00-\uDFFF])|([\uD83D][\uDC00-\uDE4F])|([\uD83D][\uDE80-\uDEFF])')
# mytext = u'<some string containing 4-byte chars>'
mytext = highpoints.sub(u'\u25FD', mytext)
Run Code Online (Sandbox Code Playgroud)