【问题标题】:In Python, how to replace all non-UTF-8 characters in a string?在 Python 中,如何替换字符串中的所有非 UTF-8 字符?
【发布时间】:2016-07-16 03:46:36
【问题描述】:

更新:真正的问题是 MySQL utf8 不支持四字节 UTF-8 字符。

关于这个主题有几个问题,但似乎都不是我的问题,除了可能是this one,接受的答案对我不起作用。

我正在使用 MySQLdb 模块在 Python 中进行编码,并且我想将一些文本放入 MySQL 数据库中。数据库配置为 UTF-8,但文本偶尔包含 non-UTF-8 四字节 UTF-8 字符。

修改数据库的 Python 代码如下所示:

connection = MySQLdb.connect(
    'localhost',
    'root',
    '',
    'mydatabase',
    charset='utf8',
    use_unicode=True)
cursor = connection.cursor()
cursor.execute(
    'update mytable set entryContent=%s where entryName=%s',
    (entryContent, entryName))
connection.commit()

它目前会产生这个警告:

./myapp.py:233: Warning: Invalid utf8 character string: 'F09286'
  (entry, word))
./myapp.py:233: Warning: Incorrect string value: '\xF0\x92\x86\xB7\xF0\x92...' for column 'entry' at row 1
  (entryname, entrycontent))

当我使用mysql 命令行客户端查看实际进入数据库的内容时,我看到内容在第一次出现 non-UTF-8 四字节时被截断UTF-8 字符。

我不在乎保留 non-UTF-8 四字节 UTF-8 字符,所以我要做的就是替换所有 non-UTF-8 del> 四字节 UTF-8 字符和一些其他有效的 UTF-8 字符,所以我可以将文本放入数据库。

【问题讨论】:

  • entry.decode().encode('ascii', 'replace')
  • @Peter Wood: 'Cognates include Hittite ???????????????? ‎(lāman)'.decode().encode('ascii', 'replace') 产生 UnicodeDecodeError: 'ascii' codec can't decode byte 0xf0 in position 25: ordinal not in range(128)
  • 对不起,'Cognates include Hittite ???????????????? ‎(lāman)'.decode('utf-8').encode('ascii', 'replace'),给'Cognates include Hittite ???????? ?(l?man)'

标签: python mysql encoding utf-8


【解决方案1】:

您需要将表格编码设置为 utf8mb4 以支持 4 字节 UTF-8 编码 - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html

此外,MySQL 驱动程序支持 Unicode 字符串,因此您应该传递 Unicode 以将您的代码从编码细节中解放出来:

例如

cursor.execute(u'update mytable set entryContent=%s where entryName=%s',
(entryContent.decode("utf-8"), entryName.decode("utf-8")))

理想情况下,当您第一次收到entryContententryName 时,它们会在您的代码中较早地被解码为Unicode。例如。打开文件或从网络接收时。

【讨论】:

  • 它被四字节的 UTF-8 字符阻塞。三字节(或更少)的 UTF-8 字符就可以了。
  • 即使您通过 Unicode(与问题中显示的 str 相对)?
  • 您是否将您的表格设置为utf8mb4 编码?见:dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
  • 不!这可能是真正的最佳答案!
  • 成功!这个答案非常有帮助,但还需要做更多的工作。在重新配置数据库、表和列以使用utf8mb4(而不仅仅是utf8)和this 之后,我发现当我请求与charset=utf8mb4 建立连接时,MySQLdb.connect() 引发了LookupError,但我可以按照this answer 中所述配置光标来更改此后连接。
【解决方案2】:

原来问题是不是我将 non-UTF-8 字符提供给 MySQL,而是我提供 四字节 UTF-8当 MySQL 仅支持三(或更少)字节 UTF-8 字符 (according to this documentation) 时,向 MySQL 发送 个字符

此方案保留所有支持的 UTF-8 字符,并将不支持的 UTF-8 字符转换为 '?':

>>> print ''.join([c if len(c.encode('utf-8')) < 4 else '?' for c in u'Cognates include Hittite ???? ‎(lāman)'])
Cognates include Hittite ???? ‎(lāman)
  • 注意保留“ā”
  • 请注意,“????”已变为“????”

我可以将此字符串放入 MySQL 中而不会出现上述警告(以及不希望的截断)。

【讨论】:

  • 是的,真正的问题是我不知道utf8mb4
【解决方案3】:

您可以使用正则表达式来删除非 ascii 字符吗?在 cmets 中使用您的示例:

>>> entry = 'Cognates include Hittite ???? ‎(lāman)'
>>> entry = ''.join([char if ord(char) < 128 else '' for char in entry])
>>> print entry
Cognates include Hittite  (lman)

这是this answer 对不同问题的轻微变化。

【讨论】:

  • 我想保留(三字节)UTF-8 字符,但这个答案会删除许多 UTF-8 字符。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-12
  • 2016-09-08
  • 2010-11-28
  • 2018-01-05
  • 1970-01-01
  • 2014-04-15
  • 2018-01-23
相关资源
最近更新 更多