为什么浏览器和Oracle DB中的EMOJI符号代码不同?

时间:2019-04-26 10:44:03

标签: oracle oracle11g emoji

我将EMOJI符号从Web应用程序保存到Oracle数据库。在html中,此符号由&#128514编码。 即我写

<html>&#128514</html>

,我将在浏览器中看到它。 但是在数据库中查询

select ascii(sym) from ..

返回值4036991106。 问题是为什么这些代码不同(128514和4036991106),以及如何将它们转换为另一种? 查询

select value from nls_database_parameters where parameter='NLS_CHARACTERSET'

返回值“ AL32UTF8”。 查询

select sym...

返回”,这是我保存的符号。

1 个答案:

答案 0 :(得分:1)

阅读文档:ASCII

  

ASCII返回数据库字符集中的十进制表示形式   char的第一个字符。

  • 4036991106是UTF-8(即AL32UTF8)中的十进制数字
  • 128514是UTF-32BE中的十进制数字

另请参阅Face with Tears of Joy U+1F602

转换不是那么简单,您可以使用此块。

DECLARE
    codepoint INTEGER := 128514;

    sg1 CHAR(2);
    sg2 CHAR(2);
    sg3 CHAR(2);
    sg4 CHAR(2);

    res VARCHAR2(20);
BEGIN   

    --128 = x80 = 10000000 -> 10xxxxxx
    --192 = xC0 = 11000000 -> 110xxxxx
    --224 = eE0 = 11100000 -> 1110xxxx
    --240 = xF0 = 11110000 -> 11110xxx

    IF codepoint <= 127 THEN        
        res := LPAD(TO_CHAR(codepoint, 'fmXX'), 2, '0');
    ELSIF codepoint <= 2047 THEN
        sg1 := TO_CHAR(192 + TRUNC(codepoint / 2**6), 'fmXX');
        sg2 := TO_CHAR(128 + codepoint MOD 2**6, 'fmXX');
        res := LPAD(sg1, 2, '0')||LPAD(sg2, 2, '0');
    ELSIF codepoint <= 65535 THEN
        sg1 := TO_CHAR(224 + TRUNC(codepoint / 2**12), 'fmXX');        
        sg2 := TO_CHAR(128 + TRUNC(codepoint / 2**6) MOD 2**6, 'fmXX');
        sg3 := TO_CHAR(128 + codepoint MOD 2**6, 'fmXX');
        res := LPAD(sg1, 2, '0')||LPAD(sg2, 2, '0')||LPAD(sg3, 2, '0');
    ELSE
        sg1 := TO_CHAR(240 + TRUNC(codepoint / 2**18), 'fmXX');        
        sg2 := TO_CHAR(128 + TRUNC(codepoint / 2**12) MOD 2**12, 'fmXX');
        sg3 := TO_CHAR(128 + TRUNC(codepoint / 2**6) MOD 2**6, 'fmXX');
        sg4 := TO_CHAR(codepoint MOD 2**6 + 128, 'fmXX');
        res := LPAD(sg1, 2, '0')||LPAD(sg2, 2, '0')||LPAD(sg3, 2, '0')||LPAD(sg4, 2, '0');
    END IF;
    DBMS_OUTPUT.PUT_LINE( 'Hex:'||res );
    DBMS_OUTPUT.PUT_LINE( 'Decimal: '||TO_NUMBER(res, 'XXXXXXXX') );

END;

结果:

Hex: F09F9882
Decimal: 4036991106

要在另一个方向进行转换,可以使用此功能:

CREATE OR REPLACE FUNCTION UNICODECHAR(uchar VARCHAR2) 
RETURN VARCHAR2 DETERMINISTIC IS

    utf16 VARCHAR2(10) := ASCIISTR(uchar);
    sg1 VARCHAR2(4);
    sg2 VARCHAR2(4);
    codepoint INTEGER;
BEGIN
    IF REGEXP_LIKE(utf16, '^\\') THEN
        IF LENGTH(utf16) = 5 THEN
            RETURN REGEXP_REPLACE(utf16, '^\\');
        ELSE
            sg1 := REGEXP_SUBSTR(utf16, '[[:xdigit:]]{4}');
            sg2 := REGEXP_SUBSTR(utf16, '[[:xdigit:]]{4}', 5);
            codepoint := 2**10 * (TO_NUMBER(sg1, 'XXXX') - TO_NUMBER('D800', 'XXXX')) + TO_NUMBER(sg2, 'XXXX') - TO_NUMBER('DC00', 'XXXX') + 2**16;
            RETURN TO_CHAR(codepoint, 'fmXXXXXX');
        END IF; 
    ELSE
        RETURN TO_CHAR(ASCII(uchar), 'fmXX');
    END IF;

END UNICODECHAR;

然后运行

select TO_NUMBER(UNICODECHAR(sym), 'XXXXXXXX') from ..