【问题标题】:CHR(0) in REGEXP_LIKEREGEXP_LIKE 中的 CHR(0)
【发布时间】:2016-09-24 11:43:10
【问题描述】:

我正在使用查询来检查 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;

我得到的输出是这样的 -

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

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

【问题讨论】:

  • @a_horse_with_no_name - Thnx 伙计......这就是我想做的......你是如何在后续行中获取代码并修改输出部分的?
  • 选择文字,点击{}按钮。单击帮助按钮 (?),您将获得有关如何格式化代码的完整说明:stackoverflow.com/editing-help
  • Here 是关于 chr(0) 的讨论

标签: oracle oracle11g oracle10g


【解决方案1】:

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

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

使用REGEXP_REPLACE 更容易看到该行为:

SELECT REGEXP_REPLACE( 'abc' || CHR(0) || 'e', CHR(0), 'd' )
FROM   DUAL;

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

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

你会得到输出:

dadbdcd_ded

其中 _ 是 CHR(0) 字符。

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

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

SELECT DUMP( REGEXP_REPLACE( 'abc' || CHR(0) || 'e', CHR(0), 'd' ) )
FROM DUAL;

输出:

Typ=1 Len=11: 100,97,100,98,100,99,100,0,100,101,100

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

REGEXP_LIKE( '1234567890', CHR(0) )

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

【讨论】:

  • 感谢您的解释!
  • 很棒的解释!谢谢:)
  • 只需一条快速评论 - 您发布的查询的输出就是简单的“dadbdcd”
  • @SubhasisM 我怀疑这是您用来显示 Oracle 查询输出而不是 Oracle 本身的客户端的问题 - 我在使用 SQL Developer 和 SQL/ 时看到了整个输出加。您可以使用 SELECT DUMP( REGEXP_REPLACE( 'abc' || CHR(0) || 'e', CHR(0), 'd' ) ) FROM DUAL; 检查 Oracle 输出的内容,您应该会看到 Typ=1 Len=11: 100,97,100,98,100,99,100,0,100,101,100(并且 Oracle 将在 CHR(0) 之后返回三个字符)。
【解决方案2】:

Aleksej 有点击败我,但 CHR(0) 是字符串终止符的值(有点像 NULL 关键字,但不完全一样)。把它想象成一个 CHR(0) 显然可以看到的内部字符串结束指示器。请注意,如果您尝试使用关键字 NULL 进行查询,它将返回零,因为没有任何内容可以与 NULL 进行比较,因此比较将失败(正如您所期望的那样)。有趣的。也许对内部工作有更多经验的人可以进一步解释,我很想听听更多。

【讨论】:

  • 正是加里!! I 它会返回 0 和 NULL。现在我不能说我对此感到惊讶,因为基本上字符串不是 NULL,因此返回 0。但是 CHR(0) 也应该发生同样的情况。我想知道如果 chr(0) 是 C 中的字符串终止符,而 sql 客户端是用 C 制作的,它会以某种方式弄乱 resexp_like。如果是这样,我想知道具体是什么方式!
【解决方案3】:

不是答案,只是一些实验,但评论太长了。

REGEXP_COUNT似乎被chr(0)搞糊涂了,把每个字符都算作chr(0);此外,它似乎发现比字符串的大小多一个。

SQL> select dump('a'), regexp_count('a', chr(0)) from dual;

DUMP('A')        REGEXP_COUNT('A',CHR(0))
---------------- ------------------------
Typ=96 Len=1: 97                        2

SQL> select dump(chr(0)), regexp_count(chr(0), chr(0)) from dual;

DUMP(CHR(0))   REGEXP_COUNT(CHR(0),CHR(0))
-------------- ---------------------------
Typ=1 Len=1: 0                           2

SQL> select dump('0123456789' || chr(0)), regexp_count('0123456789' || chr(0), chr(0)) from dual;

DUMP('0123456789'||CHR(0))                    REGEXP_COUNT('0123456789'||CHR(0),CHR(0))
--------------------------------------------- -----------------------------------------
Typ=1 Len=11: 48,49,50,51,52,53,54,55,56,57,0                                        12

LIKE 似乎表现良好,而它的 REGEXP 版本似乎失败了:

SQL> select 1 from dual where 'a' like '%' || chr(0) || '%';

no rows selected

SQL> select 1 from dual where regexp_like ('a', chr(0));

         1
----------
         1

INSTRREGEXP_INSTR 也一样

SQL> select 1 from dual where instr('a', chr(0)) != 0;

no rows selected

SQL> select 1 from dual where regexp_instr('a', chr(0)) != 0;

         1
----------
         1

在 11g XE 版本 11.2.0.2.0 - 64 位上测试

【讨论】:

    猜你喜欢
    • 2015-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-17
    • 1970-01-01
    • 2017-07-21
    • 1970-01-01
    相关资源
    最近更新 更多