REGEXP_LIKE 中的 CHR(0)

Sub*_*isM 2 oracle oracle10g oracle11g

我正在使用查询来检查 chr(0) 在 regexp_like 中的行为。

CREATE TABLE t1(a char(10));
INSERT INTO t1 VALUES('0123456789');
SELECT CASE WHEN REGEXP_LIKE(a,CHR(0)) THEN 1 ELSE 0 END col, DUMP(a)  
FROM t1;
Run Code Online (Sandbox Code Playgroud)

我得到的输出是这样的 -

col                     dump(a)
-----------             -----------------------------------
 1                     Typ=96 Len=10: 48,49,50,51,52,53,54,55,56,57
Run Code Online (Sandbox Code Playgroud)

我完全困惑了,如果没有如转储(a)所示的 chr(0),regexp_like 如何在列中找到 chr(0) 并返回 1?这里不应该返回0吗?

MT0*_*MT0 5

CHR(0)是 C 编程语言(以及其他语言)中用于终止字符串的字符。

当您传递CHR(0)给该函数时,它将依次将其传递给较低级别​​的函数,该函数将解析您传入的字符串并从该字符串构建正则表达式模式。该正则表达式模式将看到CHR(0)并认为它是字符串终止符,并忽略模式的其余部分。

使用以下命令更容易看到该行为REGEXP_REPLACE

SELECT REGEXP_REPLACE( 'abc' || CHR(0) || 'e', CHR(0), 'd' )
FROM   DUAL;
Run Code Online (Sandbox Code Playgroud)

当你运行这个时会发生什么:

  • CHR(0)被编译成正则表达式并成为字符串终止符。
  • 现在模式只是字符串终止符,因此模式是零长度字符串。
  • 然后,正则表达式与输入字符串进行匹配,它读取第一个字符a,并找到可以在 之前匹配的零长度字符串,因此它用给出的输出替换a之前匹配的任何内容。adda
  • 然后,它将重复将下一个字符转换bdb
  • 依此类推,直到到达字符串末尾,此时它将匹配零长度模式并附加最终的d.

你会得到输出:

dadbdcd_ded
Run Code Online (Sandbox Code Playgroud)

其中 _ 是CHR(0)字符。

注意:CHR(0)输入中的 不会被替换。

如果您使用的客户端程序也在截断字符串,CHR(0)您可能看不到完整的输出(这是您的客户端如何表示字符串的问题,而不是 Oracle 的输出的问题),但也可以使用以下方式显示DUMP()

SELECT DUMP( REGEXP_REPLACE( 'abc' || CHR(0) || 'e', CHR(0), 'd' ) )
FROM DUAL;
Run Code Online (Sandbox Code Playgroud)

输出:

Typ=1 Len=11: 100,97,100,98,100,99,100,0,100,101,100
Run Code Online (Sandbox Code Playgroud)

[TL;DR]那么发生了什么

REGEXP_LIKE( '1234567890', CHR(0) )
Run Code Online (Sandbox Code Playgroud)

它将创建一个零长度字符串正则表达式模式,并将在1字符之前查找零长度匹配 - 它会找到该匹配,然后返回它已找到匹配项。