无法在Oracle数据库中保存特定的特殊字符(ü)

2024-06-16 10:16:09 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图通过Python2(Flask)API从Python3(Django)应用程序中获取特殊字符(例如:ñ、ủ、é),并将其输入Oracle数据库(Oracle 19c Enterprise)。这取代了一个Java应用程序,该应用程序可以直接访问数据库,并且能够保存特殊字符而不会出现任何问题

为了使用特殊字符进行API调用,我发现必须对值进行URL编码:

>>> comment = "Joëlle Küsel Núñez-Chaillüé"
>>> urllib.parse.quote(comment).encode('utf-8')
b'Jo%C3%ABlle%20K%C3%BCsel%20N%C3%BA%C3%B1ez-Chaillu%CC%88%C3%A9'

该字符串将被发送到Python2API。我最初的尝试涉及在将其发送到Oracle之前在Python 2中对其进行解码,但是,任何将值传递到cx_Oracle的尝试都会导致'ascii' codec can't encode characters in position 3-4: ordinal not in range(128)

我试图通过直接将URL编码字符串传递给Oracle来解决这个问题:

>>> comment_blob = cx.cursor().var(cx_Oracle.BLOB)
>>> comment_blob.setvalue(0, bytes(u'{}'.format(comment.decode('utf-8'))))

在Oracle中,我尝试解码该值:

v_comment := UTL_RAW.CAST_TO_VARCHAR2( parameter );
v_comment := convert(utl_url.unescape(v_comment), 'WE8ISO8859P15');

这适用于除ủ之外的所有内容,在某些情况下,ủ会被其后面的字符覆盖(但粘贴到任何其他文本编辑器时会正确显示),有时会被更改为完全不同的字符。例如:

Joëlle Küsel Núñez-Chaillüé
Joëlle Kÿsel Núñez-Chaillüé

字符9从ü变为ÿ,虽然最后两个字符在这里看起来是正确的,但在SQL Developer中,它们组合成一个字符(通过旧Java应用程序插入的值在SQL Developer中正确显示)

你知道我为什么只对你的角色有意见吗


Tags: api数据库应用程序urlcommentjava字符oracle
2条回答

如果您有旧的cx_Oracle模块,则在创建连接时需要指定字符集,例如:

connection = cx_Oracle.connect("hr", userpwd, "dbhost.example.com/orclpdb1", encoding="UTF-8")

如果升级到cx_Oracle 8,则此字符集是默认字符集,因此可以省略encoding选项。见Setting the Client Character Set

其他两项说明:

我想出了一个有效的(虽然不理想)解决方案来解决我的问题。在我的Python3(Django)应用程序中,我将字符串转换为字符代码列表。我通过Python2API传递代码列表,而不做任何操作,然后使用PL/SQL将其转换回常规字符

Django代码:

comment = str([ord(c) for c in comment]).strip('[]').replace(' ', '')

# Send comment to API as a parameter

Python 2 API:

# Call PL/SQL function passing in the list of character codes as a string

cursor.callfunc(
    'save_comment', cx_Oracle.STRING, [comment]
)

甲骨文:

FUNCTION save_comment(p_comment VARCHAR2)
    RETURN VARCHAR2
IS
    v_comment           VARCHAR2(500) := '';
    v_remain            VARCHAR2(500);
    v_char              VARCHAR2(3);
    v_char_code         NUMBER;
BEGIN

      Comment comes in as list of character codes
      '74,111,235,108,108,101,32,75,252,115,101,108,32,78,250,241'
    v_remain := p_comment;

    WHILE v_remain IS NOT NULL LOOP

          Pop the first character code from the list
        IF v_remain LIKE '%,%' THEN
            v_char := substr(v_remain, 1, instr(v_remain, ',')-1);
            v_remain := substr(v_remain, instr(v_remain, ',') + 1);
        ELSE
            v_char := v_remain;
            v_remain := NULL;
        END IF;

          Turn character code from VARCHAR2 into NUMBER
        v_char_code := to_number(v_char);

          Convert Python char code to Oracle char code
        IF v_char_code >= 192 THEN
            v_char_code := v_char_code + 49856;
        ELSIF v_char_code > 160 THEN
            v_char_code := v_char_code + 49664;
        END IF;

          Add this character to the comment
        v_comment := v_comment || chr(v_char_code);
    END LOOP;

    RETURN v_comment;
END;

这个方便的ASCII字符代码列表是一个很好的资源:
https://www.techonthenet.com/ascii/chart.php

相关问题 更多 >