gpt4 book ai didi

python - 如何过滤(或替换)在 UTF-8 中占用超过 3 个字节的 unicode 字符?

转载 作者:IT老高 更新时间:2023-10-28 12:59:34 28 4
gpt4 key购买 nike

我正在使用 Python 和 Django,但由于 MySQL 的限制,我遇到了问题。根据MySQL 5.1 documentation ,他们的 utf8 实现不支持 4 字节字符。 MySQL 5.5将支持使用 utf8mb4 的 4 字节字符;并且,在未来的某一天,utf8 可能也会支持它。

但是我的服务器还没有准备好升级到 MySQL 5.5,因此我被限制为占用 3 个字节或更少的 UTF-8 字符。

我的问题是:如何过滤(或替换)占用超过 3 个字节的 unicode 字符?

我想用官方的 \ufffd (U+FFFD REPLACEMENT CHARACTER) 或 ? 替换所有 4 字节字符。

换句话说,我想要一个与 Python 自己的 str.encode() 非常相似的行为。方法(当传递 'replace' 参数时)。 编辑:我想要一个类似于 encode() 的行为,但我不想实际对字符串进行编码。我希望过滤后仍然有一个 unicode 字符串。

我不想在存储到 MySQL 之前转义字符,因为这意味着我需要对从数据库中获取的所有字符串进行转义,这非常烦人且不可行。

另见:

[编辑] 添加了有关建议解决方案的测试

所以到目前为止我得到了很好的答案。谢谢,人们!现在,为了选择其中一个,我做了一个快速测试,以找到最简单和最快的一个。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4 sw=4 et

import cProfile
import random
import re

# How many times to repeat each filtering
repeat_count = 256

# Percentage of "normal" chars, when compared to "large" unicode chars
normal_chars = 90

# Total number of characters in this string
string_size = 8 * 1024

# Generating a random testing string
test_string = u''.join(
unichr(random.randrange(32,
0x10ffff if random.randrange(100) > normal_chars else 0x0fff
)) for i in xrange(string_size) )

# RegEx to find invalid characters
re_pattern = re.compile(u'[^\u0000-\uD7FF\uE000-\uFFFF]', re.UNICODE)

def filter_using_re(unicode_string):
return re_pattern.sub(u'\uFFFD', unicode_string)

def filter_using_python(unicode_string):
return u''.join(
uc if uc < u'\ud800' or u'\ue000' <= uc <= u'\uffff' else u'\ufffd'
for uc in unicode_string
)

def repeat_test(func, unicode_string):
for i in xrange(repeat_count):
tmp = func(unicode_string)

print '='*10 + ' filter_using_re() ' + '='*10
cProfile.run('repeat_test(filter_using_re, test_string)')
print '='*10 + ' filter_using_python() ' + '='*10
cProfile.run('repeat_test(filter_using_python, test_string)')

#print test_string.encode('utf8')
#print filter_using_re(test_string).encode('utf8')
#print filter_using_python(test_string).encode('utf8')

结果:

  • filter_using_re()0.139 CPU 秒 内完成了 515 次函数调用(在 sub() 内置时为 0.138 CPU 秒)<
  • filter_using_python()3.413 CPU 秒 内完成了 2097923 次函数调用(join() 调用为 1.511 CPU 秒,评估为 1.900 CPU 秒生成器表达式)
  • 我没有使用 itertools 进行测试,因为......嗯......这个解决方案虽然很有趣,但相当庞大和复杂。

结论

RegEx 解决方案是迄今为止最快的解决方案。

最佳答案

在\u0000-\uD7FF 和\uE000-\uFFFF 范围内的 Unicode 字符在 UTF8 中将具有 3 个字节(或更少)的编码。\uD800-\uDFFF 范围用于多字节 UTF16。我不知道python,但你应该能够设置一个正则表达式来匹配这些范围之外。

pattern = re.compile("[\uD800-\uDFFF].", re.UNICODE)
pattern = re.compile("[^\u0000-\uFFFF]", re.UNICODE)

在问题正文中编辑从 Denilson Sá 的脚本添加 Python:

re_pattern = re.compile(u'[^\u0000-\uD7FF\uE000-\uFFFF]', re.UNICODE)
filtered_string = re_pattern.sub(u'\uFFFD', unicode_string)

关于python - 如何过滤(或替换)在 UTF-8 中占用超过 3 个字节的 unicode 字符?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3220031/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com