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

ascii function in oracle sql, for non-ascii value

在 Oracle 中 SQL:

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

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

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

这个值50049是什么意思?我期待 193

参见文档:ASCII

ASCII returns the decimal representation in the database character set of the first character of char.

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

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

等于二进制表示

也许您正在寻找

ASCIISTR('Á')

其中return是[=17=]C1,只需要转成十进制即可

前段时间我开发了这个功能,比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}|.', 1, 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('‍☠️')

应该return

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

这里 - 主要是为了我自己的教育 - 是对重音 A 的值 50049 的解释(代码点:Unicode 编码字符集中的 193)。我刚刚通过阅读 https://www.fileformat.info/info/unicode/utf8.htm Another pretty clear explanation and an example for a three-byte encoding on Wikipedia: https://en.wikipedia.org/wiki/UTF-8#Encoding

了解到这是如何工作的

编码的计算源自代码点 193,与与该代码点关联的特定字符无关。

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

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

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

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

2047 = 2^11 - 1(这就是为什么 2047 与此相关)。代码点可以表示为 11 位二进制数(可能带有前导零)。取前五位(在 left-padding 之后,长度为 0 到 11 位)并将其附加到第一个字节的强制性 110 前缀,并将代码点的后六位附加到强制性第二个字节的前缀 10。这给出了给定代码点的 UTF8 编码(两个字节)。

让我们对代码点 193(十进制)执行此操作。在二进制中,左边用 0 填充,即 00011000001。到目前为止,没什么特别的。

将其分成五位||六位:00011 和 000001.

附加强制性前缀:11000011 和 10000001。

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