chr(255)
в вашей объединенной строке обрабатывается как ноль, который не имеет длины, поэтому учитываются только другие ненулевые символы - следовательно, он получает 2, а не 4.
ASCII недействительно поднимитесь до 255, и вы на самом деле не имеете дело с ASCII.Ваш набор символов базы данных (предположительно) AL32UTF8, который является многобайтовым набором символов.Из Резюме FileFormat.Info :
Для любого символа, равного или ниже 127 (шестнадцатеричный 0x7F), представление UTF-8 составляет один байт.Это всего лишь младшие 7 битов полного значения Юникода.Это также то же самое, что и значение ASCII.
Для символов, равных или ниже 2047 (шестнадцатеричный 0x07FF), представление UTF-8 разбивается на два байта.В первом байте будут установлены два старших бита, а третий бит сброшен (т. Е. От 0xC2 до 0xDF).У второго байта будет установлен верхний бит и очищен второй бит (т. Е. От 0x80 до 0xBF).
И из документации для chr()
:
Для многобайтовых наборов символов n должно преобразовываться в одну целую кодовую точку.Недопустимые кодовые точки не проверяются, и результат определения недопустимых кодовых точек является неопределенным.
Для UTF8 нет полной кодовой точки 255 / FF, поэтому chr(255)
недопустимо.Фактически, в соответствии со спецификацией , нет никаких кодовых точек с октетом FF.
Вы могли бы ожидать, что оно будет отображено как 'ÿ';если вы используете кодировку, в которой она действительна, например AL16UTF16:
select chr(255 using nchar_cs), dump(chr(255 using nchar_cs), 1016) as chr_dump,
unistr('\00ff'), dump(unistr('\00ff'), 1016) as unistr_dump
from dual;
C CHR_DUMP U UNISTR_DUMP
- ---------------------------------------- - --------------------------------------------------
ÿ Typ=1 Len=2 CharacterSet=AL16UTF16: 0,ff ÿ Typ=1 Len=2 CharacterSet=AL16UTF16: 0,ff
, но из-за способа кодирования UTF8 это (и все, что выше 127) на самом деле является несколькими байтами, C3BF
.
Здесь немного интереснее то, как Oracle обрабатывает этот недопустимый символ.Само по себе вы можете видеть, что он существует и является недействительным, но когда он объединяется с другим (действительным или недействительным) символом, он по существу игнорируется:
with t (descr, str) as (
select 'chr(255)', chr(255) from dual
union all select 'chr(255)||chr(255)', chr(255)||chr(255) from dual
union all select q'['*'||chr(255)]', '*'||chr(255) from dual
union all select q'[chr(255)||'$']', chr(255)||'$' from dual
union all select q'['*'||chr(255)||'$']', '*'||chr(255)||'$' from dual
union all select q'['*'||chr(255)||'$'||chr(255)]', '*'||chr(255)||'$'||chr(255) from dual
union all select q'[chr(255)||'*'||chr(255)||'$']', chr(255)||'*'||chr(255)||'$' from dual
union all select q'['*'||chr(255)||chr(255)||'$']', '*'||chr(255)||chr(255)||'$' from dual
union all select q'['ÿ']', 'ÿ' from dual
union all select 'chr(127)||chr(127)', chr(127)||chr(127) from dual
union all select 'chr(127)||chr(128)', chr(127)||chr(128) from dual
union all select 'chr(128)||chr(127)', chr(128)||chr(127) from dual
union all select 'chr(128)||chr(128)', chr(128)||chr(128) from dual
)
select descr, str, dump(str, 1016) as str_dump, length(str) as str_length
from t;
DESCR ST STR_DUMP STR_LENGTH
---------------------------- -- -------------------------------------------------- ----------
chr(255) ? Typ=1 Len=1 CharacterSet=AL32UTF8: ff 1
chr(255)||chr(255) NULL
'*'||chr(255) * Typ=1 Len=1 CharacterSet=AL32UTF8: 2a 1
chr(255)||'$' $ Typ=1 Len=1 CharacterSet=AL32UTF8: 24 1
'*'||chr(255)||'$' *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
'*'||chr(255)||'$'||chr(255) *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
chr(255)||'*'||chr(255)||'$' *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
'*'||chr(255)||chr(255)||'$' *$ Typ=1 Len=2 CharacterSet=AL32UTF8: 2a,24 2
'ÿ' ÿ Typ=1 Len=2 CharacterSet=AL32UTF8: c3,bf 1
chr(127)||chr(127) Typ=1 Len=2 CharacterSet=AL32UTF8: 7f,7f 2
chr(127)||chr(128) Typ=1 Len=1 CharacterSet=AL32UTF8: 7f 1
chr(128)||chr(127) Typ=1 Len=1 CharacterSet=AL32UTF8: 7f 1
chr(128)||chr(128) NULL
Последние несколько примеров показывают, что это не является конкретнымдо 255, это что-то выше 127, это проблема, потому что UTF8 переходит с 127 / 7F (все еще один байт) на 128 / C280 (два байта).(Вы можете увидеть скачок здесь , например.)
И вот короткая демонстрация того, что конкатенация любого недопустимого символа, сформированного с использованием 128-255, обрабатывается как нуль независимо от того, с чем он соединяется:
with t (n) as (
select level from dual connect by level <= 255
)
select count(*), min(t1.n), max(t1.n), min(t1.n), max(t2.n)
from t t1
cross join t t2
where chr(t1.n)||chr(t2.n) is null
order by t1.n, t2.n;
COUNT(*) MIN(T1.N) MAX(T1.N) MIN(T1.N) MAX(T2.N)
---------- ---------- ---------- ---------- ----------
16384 128 255 128 255