【问题标题】:Warning raised by inserting 4-byte unicode to mysql向 mysql 插入 4 字节 unicode 引发的警告
【发布时间】:2012-06-03 15:28:13
【问题描述】:

看下面:

/home/kinka/workspace/py/tutorial/tutorial/pipelines.py:33: Warning: Incorrect string 
value: '\xF0\x9F\x91\x8A\xF0\x9F...' for column 't_content' at row 1
n = self.cursor.execute(self.sql, (item['topic'], item['url'], item['content']))

字符串'\xF0\x9F\x91\x8A,实际上是一个4字节的unicode:u'\U0001f62a'。 mysql 的字符集是 utf-8,但插入 4 字节 unicode 会截断插入的字符串。 我google了一下这样的问题,发现5.5.3下的mysql不支持4字节unicode,可惜我的是5.5.224。 我不想升级mysql服务器,所以我只想在python中过滤4字节的unicode,我尝试使用正则表达式但失败了。 那么,有什么帮助吗?

【问题讨论】:

  • 那是 FISTED HAND SIGN 彩色表情符号:????...
  • @MartijnPieters - unicodedata.name("\U0001f62a")'SLEEPY FACE'(在 utf-8 中是 b'\xf0\x9f\x98\xaa'),所以这里有些东西不合适......
  • 其实就是一张睡眼惺忪的脸。我正在从sina weibo(中国的推特)刮网页,我刮了这样的SLEEP FACE
  • 是的,'\xF0\x9F\x91\x8A'.decode('utf8')u'\U0001f44a',也就是 'FISTED HAND SIGN' :-)

标签: python mysql regex astral-plane


【解决方案1】:

如果 MySQL 无法处理 4 字节或更多字节的 UTF-8 代码,那么您必须过滤掉代码点 \U00010000 上的所有 unicode 字符; UTF-8 将低于该阈值的代码点编码为 3 个字节或更少。

您可以为此使用正则表达式:

>>> import re
>>> highpoints = re.compile(u'[\U00010000-\U0010ffff]')
>>> example = u'Some example text with a sleepy face: \U0001f62a'
>>> highpoints.sub(u'', example)
u'Some example text with a sleepy face: '

或者,您可以将.translate() function 与仅包含None 值的映射表一起使用:

>>> nohigh = { i: None for i in xrange(0x10000, 0x110000) }
>>> example.translate(nohigh)
u'Some example text with a sleepy face: '

但是,创建翻译表会消耗大量内存并且需要一些时间来生成;这可能不值得您付出努力,因为正则表达式方法更有效。

这一切都假定您使用的是 UCS-4 编译的 python。如果你的 python 是在 UCS-2 支持下编译的,那么你只能在正则表达式中使用高达 '\U0000ffff' 的代码点,你一开始就不会遇到这个问题。

我注意到,从 MySQL 5.5.3 开始,新添加的 utf8mb4 codec 确实支持完整的 Unicode 范围。

【讨论】:

  • 我试过你的代码,但它不起作用。它是\U(大写u)。不过,你的想法真的很有启发性,谢谢!
  • 你说的很对;更正为使用正确的 8 字节转义序列。由于使用 UCS2 编译的 python,起初我遇到了一些麻烦:-P
  • 但就我而言,是否小写真的很重要。我使用的是highpoints = re.compile(u'[\U00010000-\U0001ffff]'),它可以工作。好像在我的电脑上(是python版本的问题吗?我的是python 2.7)。用大写的\U,unicode支持的范围更大。
  • 不,你说的很对。我也刚刚降低了下限,意识到我误读了 UTF-8 表。
  • 知道为什么会出现错误:re.compile(u'[\U00010000-\U0010ffff]')"/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/re.py", line 244, in _compileraise error, v # invalid expressionsre_constants.error: bad character range
【解决方案2】:

我认为你应该使用 utf8mb4 排序规则而不是 utf8 并运行

SET NAMES UTF8MB4

与数据库连接后(linklinklink

【讨论】:

  • 将连接设置为使用utf8mb4 是最好的方法,但您不应该使用SET NAMES。此命令会更改服务器端的连接设置,但不会让客户端库知道更改,这意味着使用 C mysql_real_escape_string API 的客户端库中的任何内容都可能会得到不好的结果。如果东亚多字节编码是涉及的一个或两个字符集,这可能会导致 SQL 注入安全漏洞。字符集应在连接时设置;在 python-mysql 中,这将通过 charset 参数到 connect() 来完成。
【解决方案3】:

没有正则表达式和翻译的字符串的简单规范化:

def normalize_unicode(s):
    return ''.join([ unichr(k) if k < 0x10000 else 0xfffd for k in [ord(c) for c in s]])

【讨论】:

    猜你喜欢
    • 2019-08-28
    • 1970-01-01
    • 2017-09-21
    • 2020-09-09
    • 2013-07-05
    • 1970-01-01
    • 1970-01-01
    • 2011-07-11
    相关资源
    最近更新 更多