oracle sql中的ascii函数,用于非ascii值

问题描述

在Oracle sql中:

当我们将任何非ASCII字符传递给ASCII函数时,它将返回一些数字。我们如何解释这个数字。如果我们将字符集设置为AL32UTF8,为什么它不为给定字符返回Unicode点

select * from nls_database_parameters where parameter = 'NLS_CHaraCTERSET';--AL32UTF8

select ascii('Á') from dual;--50049

该值50049是什么意思?我原本希望是193

解决方法

在这里-主要是出于我个人的学习-是带重音符号A的值50049的解释(代码点:Unicode编码字符集中的193)。通过阅读https://www.fileformat.info/info/unicode/utf8.htm另一个非常清楚的解释以及一个关于Wikipedia的三字节编码的示例,我刚刚了解了它的工作原理:https://en.wikipedia.org/wiki/UTF-8#Encoding

编码的计算是从代码点193派生的,与与该代码点关联的特定字符无关。

UTF-8使用相对简单的方案来编码多达1,141,111(或者可能是现在更多的代码点);现在让我们只担心达到该上限的代码点即可。

从1到127(十进制)的代码点被编码为一个字节,等于该代码点(因此,当用二进制表示时,该字节始终具有前导零)。

从128到2047的代码点被编码为两个字节。以二进制表示的第一个字节始终以110开头,第二个字节始终以10开头。以110开头的字节始终是两字节编码的第一个字节,而以10开头的字节始终是“继续”。多字节编码中的字节(第二,第三或第四)。这些强制性前缀是编码方案的一部分(UTF8编码的“规则”);它们是规则中的硬编码值。

因此:对于从128到2047的代码点,编码使用两个字节,二进制格式的确切格式为110xxxxx和10xxxxxx。第一个字节的后五位(位)加上第二个字​​节的后六位(总计:11位)是代码点的二进制表示形式(必须编码的值从128到2047)。

2047 = 2 ^ 11-1(这就是2047在这里有意义的原因)。代码点可以表示为11位二进制数(可能带有前导零)。取前五位(用0填充到11位长度左填充后)并将其附加到第一个字节的强制性110前缀,并获取代码点的后六位并将其附加至强制性前缀10第二个字节的这样就可以给出给定代码点的UTF8编码(两个字节)。

让我们为代码点193(十进制)这样做。以二进制形式,左侧填充0,即00011000001。到目前为止,没有任何花哨的内容。

将其拆分为五个位||六位:00011和000001。

附加必需的前缀: 110 00011和 10 000001。

以十六进制形式重写它们:\ xC3和\ x81。把它们放在一起;这是十六进制C381或十进制50049。

,

请参阅文档:ASCII

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

UTF-8中字符Á(U + 00C1)的二进制值为xC381,即十进制50049。

193是代码点。对于UTF-8,仅对于字符U + 0000-U + 007F(0-127),代码点等于二进制表示。对于UTF-16BE,代码点仅对于字符U + 0000-U + FFFF(0-65535)等于二进制表示形式,

也许您正在寻找

ASCIISTR('Á')

返回\00C1,只需要将其转换为十进制值即可。

前一段时间,我开发了此功能,该功能比ASCIISTR更高级,它也可以处理多码字符。

CREATE OR REPLACE TYPE VARCHAR_TABLE_TYPE AS TABLE OF VARCHAR2(100);


FUNCTION UNICODECHAR(uchar VARCHAR2) RETURN VARCHAR_TABLE_TYPE IS

    UTF16 VARCHAR2(32000) := ASCIISTR(uchar);
    UTF16_Table VARCHAR_TABLE_TYPE := VARCHAR_TABLE_TYPE();
    sg1 VARCHAR2(4);
    sg2 VARCHAR2(4);
    codepoint INTEGER;

    res VARCHAR_TABLE_TYPE := VARCHAR_TABLE_TYPE();
    i INTEGER;
BEGIN
 
    IF uchar IS NULL THEN
        RETURN VARCHAR_TABLE_TYPE();
    END IF;
    
    SELECT REGEXP_SUBSTR(UTF16,'(\\[[:xdigit:]]{4})|.',1,LEVEL)
    BULK COLLECT INTO UTF16_Table  
    FROM dual
    CONNECT BY REGEXP_SUBSTR(UTF16,'\\[[:xdigit:]]{4}|.',LEVEL) IS NOT NULL;
    
    i := UTF16_Table.FIRST;
    WHILE i IS NOT NULL LOOP
        res.EXTEND;
        IF REGEXP_LIKE(UTF16_Table(i),'^\\') THEN
            IF REGEXP_LIKE(UTF16_Table(i),'^\\D(8|9|A|B)') THEN
                sg1 := REGEXP_SUBSTR(UTF16_Table(i),'[[:xdigit:]]{4}');
                i := UTF16_Table.NEXT(i);
                sg2 := REGEXP_SUBSTR(UTF16_Table(i),'[[:xdigit:]]{4}');
                codepoint := 2**10 * (TO_NUMBER(sg1,'XXXX') - TO_NUMBER('D800','XXXX')) + TO_NUMBER(sg2,'XXXX') - TO_NUMBER('DC00','XXXX') + 2**16;
                res(res.LAST) := 'U+'||TO_CHAR(codepoint,'fmXXXXXX');
            ELSE
                res(res.LAST) := 'U+'||REGEXP_REPLACE(UTF16_Table(i),'^\\');
            END IF; 
        ELSE
            res(res.LAST) := 'U+'||LPAD(TO_CHAR(ASCII(UTF16_Table(i)),'fmXX'),4,'0');
        END IF;     
        i := UTF16_Table.NEXT(i);
    END LOOP;
    RETURN res;

END UNICODECHAR;

尝试使用https://unicode.org/emoji/charts/full-emoji-list.html#1f3f3_fe0f_200d_1f308

中的一些示例
UNICODECHAR('?‍☠️')

应该返回

U+1F3F4 
U+200D 
U+2620 
U+FE0F