在Flask/Python中正确处理emoji的方法是什么?

3 投票
1 回答
1920 浏览
提问于 2025-04-20 15:44

我正在做一个API,结果在处理emoji的时候让我快疯了,使用的是Flask/Python和emoji编码 :P

在本地服务器上,我没有遇到任何问题,emoji图标在字符串长度中占用“两个位置”,而客户端(用HTML和JavaScript写的)也是这样处理的。但是当我把它部署到AWS EB上时,emoji图标“只占一个位置”,这样字符串的总长度就变小了,我完全不知道为什么会这样..

我写了一个小代码示例来说明发生了什么:

@api10.route('/prueba2', methods=['GET','POST'])
def prueba2():
    que = request.form.get("que", None)

    SEP = "\n"
    if request.form.get("web", None) == "ok":
        SEP = "<br />"

    out = "QUE: '%s'%s" % (que,SEP)
    out += "REP: '%s'%s%s" % (repr(que),SEP,SEP)
    out += "LENGTH: '%d'%s%s" % (len(que),SEP,SEP)
    out += "TYPE: '%s'%s%s" % (str(type(que)).replace("<", ""),SEP,SEP)
    for index,letter in enumerate(que):
        out += "%d -> %s%s" % (index,letter,SEP)

    return out, 200, {'Content-Type': 'text/html; charset=utf-8'}

本地响应: 本地响应在Chrome Postman中

AWS EB响应: AWS EB响应在Chrome Postman中

两个响应的头信息是一样的:

Content-Type →text/html; charset=utf-8
Date →Tue, 09 Sep 2014 11:47:03 GMT
Server →Werkzeug/0.9.6 Python/2.6.8

但是在AWS EB上,“连接”是“保持活动”(当然“内容长度”是不相等的)

这两个实现都在Python 2.6上运行(EC2使用这个版本,而我本地有一个虚拟环境是python26)

1 个回答

3

好的,我现在知道为什么会发生那种情况了...

> 服务器端

虽然这两个版本都是在 Python 2.6 上运行的,但 AWS EB 的 Python 版本是支持 UCS4 的,而本地(Mac OS X)的 Python 2.6 是支持 UCS2 的。关于 UCS 的更多信息可以查看这里

AWS EB EC2:
>>> import sys
>>> print sys.maxunicode
1114111
本地 Python 2.6.8 安装:
>>> import sys
>>> print sys.maxunicode
65535

最后我决定,为了我们的项目,使用支持 UCS4 的 Python 2.6 更好,所以我需要更新我的 Python 安装(Mac OS X 10.9.4):

下载并安装 Python 2.6.8(与 EC2 实例相同):

$ curl -O https://www.python.org/ftp/python/2.6.8/Python-2.6.8.tgz
$ tar xzvf Python-2.6.8.tgz
$ cd Python-2.6.8
$ ./configure --disable-framework --disable-toolbox-glue OPT="-fast -arch x86_64 -Wall -Wstrict-prototypes -fno-common -fPIC" --enable-unicode=ucs4 LDFLAGS="-arch x86_64"
$ make
$ sudo make install

创建新的虚拟环境并安装依赖:

$ virtualenv -p /usr/local/bin/python2.6 venv_ayf_eb_26
$ . venv_ayf_eb_26/bin/activate
$ pip install -r requirements.txt

> 客户端

现在在客户端(JavaScript)我们需要更新字符串的循环方式,因为 ECMAScript 5- 使用的是 UCS2

所以为了读取“真实的字符串/符号长度”,我们使用:

String.prototype.getSymbols = function() {
    var length = this.length;
    var index = -1;
    var output = [];
    var character;
    var charCode;
    while (++index < length) {
        character = this.charAt(index);
        charCode = character.charCodeAt(0);
        if (charCode >= 0xD800 && charCode <= 0xDBFF) {
            // note: this doesn’t account for lone high surrogates
            output.push(character + this.charAt(++index));
        } else {
            output.push(character);
        }
    }
    return output;
};
String.prototype.realLength = function() {
    return this.getSymbols().length;
};

循环:

// GET original_text over REST API
text = original_text.getSymbols();
for ( var i=0; i<original_text.length; i++) { /* DO SOMETHING */ }

参考资料

  1. 每个软件开发者绝对必须了解的 Unicode 和字符集的基本知识(没有借口!) - Joel Spolsky
  2. Unipain: 实用的 Unicode - Ned Batchelder
  3. 通用字符集 - 维基百科
  4. ECMAScript - 维基百科
  5. ECMAScript® 语言规范 (5.1) - Ecma International
  6. JavaScript 有一个 Unicode 问题 - Mathias Bynens
  7. Python,转换 4 字节字符以避免 MySQL 错误“字符串值不正确” - StackOverflow
  8. 如何判断 Python 是用 UCS-2 还是 UCS-4 编译的? - StackOverflow

撰写回答